sourceextensions/audio/lib/Audio.xtl

1⍝# Audio.xtl -- the facade of the audio extension: decode Ogg Vorbis, MP3 2⍝# and WAV, play them on the sound device, read what is playing as arrays, 3⍝# and play arrays. 4⍝# Import: "au:" u_se< "Audio" 5⍝# Run with xetal-x (xetal-x --ext DIR puts this directory on XETAL_PATH). 6⍝# With XETAL_HEADLESS=1 (or XETAL_AUDIO=off) nothing sounds and playback 7⍝# advances a 60th of a second per au:w_indow (or au:p_layed) -- for tests. 8⍝# Each signature line is written out by the binding macro (lib/Ffi.xtlm). 9 10ᶠᶠⁱ⁼u̲se< "Ffi" 11 12⍝# au:o_pen path: an audio file (Ogg Vorbis, MP3 or WAV); its id. 13"o_pen : text -> int" ᶠᶠⁱb̲ind< "audio/open"
ᶠᶠⁱb̲ind< expands to
ˡo̲pen ← { a →
  pa ← a ⎕N̲PUT "ext:audio/open?text"
  f̲loor f̲irst n̲umbers ⎕N̲GET "ext:audio/open"
}
14⍝# au:i_nfo id: sample rate, channels, frames, seconds (-1 when unknown). 15"i_nfo : float -> floats" ᶠᶠⁱb̲ind< "audio/info"
ᶠᶠⁱb̲ind< expands to
ˡi̲nfo ← { a →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/info?float=" c̲at f̲ormat s̲hape a
  v ← n̲umbers ⎕N̲GET "ext:audio/info"
  (f̲loor n̲umbers ⎕N̲GET "ext:audio/info?shape") r̲eshape v
}
16⍝# id au:c_hunk n: the next n frames read in order (apart from playback): 17⍝# a 2 by m matrix, left over right; fewer at the end, none after it. 18"c_hunk : float float -> floats" ᶠᶠⁱb̲ind< "audio/chunk"
ᶠᶠⁱb̲ind< expands to
ˡc̲hunk ← { a b →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/chunk?float=" c̲at f̲ormat s̲hape a
  pb ← (f̲ormat r̲avel f̲loat b) ⎕N̲PUT "ext:audio/chunk?float=" c̲at f̲ormat s̲hape b
  v ← n̲umbers ⎕N̲GET "ext:audio/chunk"
  (f̲loor n̲umbers ⎕N̲GET "ext:audio/chunk?shape") r̲eshape v
}
19⍝# au:p_lay! id: start or resume playing; the id. 20"p_lay! : float -> int" ᶠᶠⁱb̲ind< "audio/play"
ᶠᶠⁱb̲ind< expands to
ˡp̲lay! ← { a →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/play?float=" c̲at f̲ormat s̲hape a
  f̲loor f̲irst n̲umbers ⎕N̲GET "ext:audio/play"
}
21⍝# au:p_ause! id: pause; the id. 22"p_ause! : float -> int" ᶠᶠⁱb̲ind< "audio/pause"
ᶠᶠⁱb̲ind< expands to
ˡp̲ause! ← { a →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/pause?float=" c̲at f̲ormat s̲hape a
  f̲loor f̲irst n̲umbers ⎕N̲GET "ext:audio/pause"
}
23⍝# id au:s_eek! seconds: move playback there; the second it landed on. 24"s_eek! : float float -> float" ᶠᶠⁱb̲ind< "audio/seek"
ᶠᶠⁱb̲ind< expands to
ˡs̲eek! ← { a b →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/seek?float=" c̲at f̲ormat s̲hape a
  pb ← (f̲ormat r̲avel f̲loat b) ⎕N̲PUT "ext:audio/seek?float=" c̲at f̲ormat s̲hape b
  f̲irst n̲umbers ⎕N̲GET "ext:audio/seek"
}
25⍝# au:p_osition id: the second playing now. 26"p_osition : float -> float" ᶠᶠⁱb̲ind< "audio/position"
ᶠᶠⁱb̲ind< expands to
ˡp̲osition ← { a →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/position?float=" c̲at f̲ormat s̲hape a
  f̲irst n̲umbers ⎕N̲GET "ext:audio/position"
}
27⍝# id au:w_indow n: the n frames ending at what plays now, 2 by n (left 28⍝# over right; zeros before the start). Call it once a frame. 29"w_indow : float float -> floats" ᶠᶠⁱb̲ind< "audio/window"
ᶠᶠⁱb̲ind< expands to
ˡw̲indow ← { a b →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/window?float=" c̲at f̲ormat s̲hape a
  pb ← (f̲ormat r̲avel f̲loat b) ⎕N̲PUT "ext:audio/window?float=" c̲at f̲ormat s̲hape b
  v ← n̲umbers ⎕N̲GET "ext:audio/window"
  (f̲loor n̲umbers ⎕N̲GET "ext:audio/window?shape") r̲eshape v
}
30⍝# au:s_tate id: 0 stopped (not started, or at the end), 1 playing, 2 paused. 31"s_tate : float -> int" ᶠᶠⁱb̲ind< "audio/state"
ᶠᶠⁱb̲ind< expands to
ˡs̲tate ← { a →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/state?float=" c̲at f̲ormat s̲hape a
  f̲loor f̲irst n̲umbers ⎕N̲GET "ext:audio/state"
}
32⍝# au:c_lose! id: stop and forget a file; a voice plays out what is queued 33⍝# (or writes its WAV) first; 1. 34"c_lose! : float -> int" ᶠᶠⁱb̲ind< "audio/close"
ᶠᶠⁱb̲ind< expands to
ˡc̲lose! ← { a →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/close?float=" c̲at f̲ormat s̲hape a
  f̲loor f̲irst n̲umbers ⎕N̲GET "ext:audio/close"
}
35 36⍝## Sound out of arrays 37 38⍝# au:o_utput rate: a voice playing what the program queues, at rate 39⍝# frames a second (22050 is plenty for a synthesizer); its id. 40"o_utput : float -> int" ᶠᶠⁱb̲ind< "audio/output"
ᶠᶠⁱb̲ind< expands to
ˡo̲utput ← { a →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/output?float=" c̲at f̲ormat s̲hape a
  f̲loor f̲irst n̲umbers ⎕N̲GET "ext:audio/output"
}
41⍝# id au:q_ueue! samples: play these after what is queued -- a vector 42⍝# (mono) or 2 by n (left over right), from -1 to 1; the seconds now 43⍝# queued ahead. With no device (XETAL_AUDIO=off) nothing sounds, and 44⍝# XETAL_AUDIO_WAV=FILE collects everything queued in a WAV file. 45"q_ueue! : float float -> float" ᶠᶠⁱb̲ind< "audio/queue"
ᶠᶠⁱb̲ind< expands to
ˡq̲ueue! ← { a b →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/queue?float=" c̲at f̲ormat s̲hape a
  pb ← (f̲ormat r̲avel f̲loat b) ⎕N̲PUT "ext:audio/queue?float=" c̲at f̲ormat s̲hape b
  f̲irst n̲umbers ⎕N̲GET "ext:audio/queue"
}
46⍝# id au:w_ait! seconds: wait until at most that much is queued, so a 47⍝# program can stream without hurrying; the seconds played so far. 48"w_ait! : float float -> float" ᶠᶠⁱb̲ind< "audio/wait"
ᶠᶠⁱb̲ind< expands to
ˡw̲ait! ← { a b →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/wait?float=" c̲at f̲ormat s̲hape a
  pb ← (f̲ormat r̲avel f̲loat b) ⎕N̲PUT "ext:audio/wait?float=" c̲at f̲ormat s̲hape b
  f̲irst n̲umbers ⎕N̲GET "ext:audio/wait"
}
49⍝# au:p_layed id: the second a voice is playing now -- to draw what is 50⍝# heard (with no device, a 60th of a second more each time it is asked). 51"p_layed : float -> float" ᶠᶠⁱb̲ind< "audio/played"
ᶠᶠⁱb̲ind< expands to
ˡp̲layed ← { a →
  pa ← (f̲ormat r̲avel f̲loat a) ⎕N̲PUT "ext:audio/played?float=" c̲at f̲ormat s̲hape a
  f̲irst n̲umbers ⎕N̲GET "ext:audio/played"
}
52 53⍝# The native package behind these functions. 54ˡpackage ← "audio"