Skip to content

Commit

Permalink
Initial proof-of-concept snd-s7 client
Browse files Browse the repository at this point in the history
  • Loading branch information
russtoku authored and Olical committed Jul 11, 2023
1 parent 4e9c543 commit ad574db
Show file tree
Hide file tree
Showing 8 changed files with 426 additions and 3 deletions.
Binary file added dev/snd-s7/one-tone.snd
Binary file not shown.
70 changes: 70 additions & 0 deletions dev/snd-s7/sandbox.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
;; Sample snd/s7 code
;;
;;--------------------------------------------------------------------------------
;; NOTES:
;;
;; 1. This was tested with version 23.5 of snd downloaded from Sourceforge and
;; compiled on a Macbook Air 13-inch Early 2015 running Monterey (12.6.7).
;; snd program is compiled without a GUI (--without-gui).
;;
;; **********************************************************************
;; *** Unfortunately, it doesn't accept multi-line input being sent ***
;; *** to it from Conjure. ***
;; **********************************************************************
;;
;; 2. Setting command to "snd" or "snd -noinit" doesn't make a difference in
;; the snd REPL accepting multi-line input.
;;
;; - On the Neovim command line:
;; :let g:conjure#client#snd#stdio#command="snd -noinit"
;; :echo g:conjure#client#snd#stdio#command
;;
;; 3. Setting command to "snd -noinit" results in no return value from the
;; REPL.
;;
;; 4. Turn on debugging to see what's being sent to and received from the snd
;; REPL.
;;
;; - On the Neovim command line:
;; :let g:conjure#debug=v:true
;; :echo g:conjure#debug
;;
;;--------------------------------------------------------------------------------

;; From https://github.com/Olical/conjure/issues/507
;; - @kflak (Kenneth Flak) 06/24/2023
;; Changed to use test.snd.
;; - This doesn't work because the snd/s7 REPL that this was originally tested
;; with. See the NOTES above.
(begin
(open-sound "test.snd")
(scale-channel 0.1)
(save-sound-as "test-scaled.wav"))

;; Start here and evaluated in order.
;; 1. Create a sound consisting of two violin tones and save in "test.snd" file.
;; test.snd will be overwritten each time that you evaluate this form.
;; From "clm-load" section of https://ccrma.stanford.edu/software/snd/snd/sndscm.html
(with-sound () (fm-violin 0 1 440 .1) (fm-violin 1 1 660 .1)) ;=> "test.snd"
(play 0) ;; I think this is 0.
(play) ;; What sound instance does this play? Seems like the last one loaded
;; or created; not played.

;; 2. The value passed to scale-channel determines the volume of the sound.
(begin (open-sound "test.snd") (scale-channel 1.5) (save-sound-as "test-scaled.wav"))
(play 1) ;; test-scaled.wav is 1.
(open-sound "test-scaled.wav")
(play 2) ;; should be 2.

(scale-channel 2.0) ;; This makes the previous sound (#2) lounder.
(play 2) ;; check it out

;; 3. Load some other sounds.
;; This assumes that you started Neovim in the clone of the Conjure repo
;; on the branch that this is on.
(open-sound "dev/snd-s7/one-tone.snd")
(play 3)

(open-sound "dev/snd-s7/three-tone.snd")
(play 4)

Binary file added dev/snd-s7/three-tone.snd
Binary file not shown.
196 changes: 196 additions & 0 deletions fnl/conjure/client/snd-s7/stdio.fnl
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
;;------------------------------------------------------------
;; A client for snd/s7 (sound editor with s7 scheme scripting)
;;
;; Based on: fnl/conjure/client/scheme/stdio.fnl
;; fnl/conjure/client/sql/stdio.fnl
;;
;; The `snd` program should be runnable on the command line.
;;
;; NOTE: Conflicts with the Scheme client due to the same filetype suffix.
;; For testing the proof-of-concept, this client replaces the Scheme
;; client in fnl/conjure/config.fnl.
;;
;;------------------------------------------------------------

(module conjure.client.snd-s7.stdio
{autoload {a conjure.aniseed.core
str conjure.aniseed.string
nvim conjure.aniseed.nvim
stdio conjure.remote.stdio-rt
config conjure.config
mapping conjure.mapping
client conjure.client
log conjure.log
ts conjure.tree-sitter}
require-macros [conjure.macros]})

(config.merge
{:client
{:snd-s7
{:stdio
{:mapping {:start "cs"
:stop "cS"
:interrupt "ei"}
:command "snd"
:prompt_pattern "> "}}}})

(def- cfg (config.get-in-fn [:client :snd-s7 :stdio]))

(defonce- state (client.new-state #(do {:repl nil})))

(def buf-suffix ".scm")
(def comment-prefix "; ")
(def form-node? ts.node-surrounded-by-form-pair-chars?)

(defn- with-repl-or-warn [f opts]
(let [repl (state :repl)]
(if repl
(f repl)
(log.append [(.. comment-prefix "No REPL running")]))))

;;;;-------- from client/sql/stdio.fnl ----------------------
(defn- format-message [msg]
(str.split (or msg.out msg.err) "\n"))

(defn- remove-blank-lines [msg]
(->> (format-message msg)
(a.filter #(not (= "" $1)))))

(defn- display-result [msg]
(log.append (remove-blank-lines msg)))

(defn ->list [s]
(if (a.first s)
s
[s]))

(defn eval-str [opts]
(with-repl-or-warn
(fn [repl]
(repl.send
(.. opts.code "\n")
(fn [msgs]
(let [msgs (->list msgs)]
(when opts.on-result
(opts.on-result (str.join "\n" (remove-blank-lines (a.last msgs)))))
(a.run! display-result msgs))
)
{:batch? false}))))

;;;;-------- End from client/sql/stdio.fnl ------------------

;;;;-------- from client/scheme/stdio.fnl -------------------
; (defn unbatch [msgs]
; {:out (->> msgs
; (a.map #(or (a.get $1 :out) (a.get $1 :err)))
; (str.join ""))})
;
; (defn format-msg [msg]
; (->> (-> msg
; (a.get :out)
; (string.gsub "^%s*" "")
; (string.gsub "%s+%d+%s*$" "")
; (str.split "\n"))
; (a.map
; (fn [line]
; (if
; (not (cfg [:value_prefix_pattern]))
; line
;
; (string.match line (cfg [:value_prefix_pattern]))
; (string.gsub line (cfg [:value_prefix_pattern]) "")
;
; (.. comment-prefix "(out) " line))))
; (a.filter #(not (str.blank? $1)))))
;
;
; (defn eval-str [opts]
; (with-repl-or-warn
; (fn [repl]
; (repl.send
; (.. opts.code "\n")
; (fn [msgs]
; (let [msgs (-> msgs unbatch format-msg)]
; (opts.on-result (a.last msgs))
; (log.append msgs)))
; {:batch? true}))))
;
;;;;-------- End from client/scheme/stdio.fnl ---------------

(defn eval-file [opts]
(eval-str (a.assoc opts :code (.. "(load \"" opts.file-path "\")"))))

(defn interrupt []
(with-repl-or-warn
(fn [repl]
(log.append [(.. comment-prefix " Sending interrupt signal.")] {:break? true})
(repl.send-signal vim.loop.constants.SIGINT))))

(defn- display-repl-status [status]
(log.append
[(.. comment-prefix
(cfg [:command])
" (" (or status "no status") ")")]
{:break? true}))

(defn stop []
(let [repl (state :repl)]
(when repl
(repl.destroy)
(display-repl-status :stopped)
(a.assoc (state) :repl nil))))

(defn start []
(if (state :repl)
(log.append [(.. comment-prefix "Can't start, REPL is already running.")
(.. comment-prefix "Stop the REPL with "
(config.get-in [:mapping :prefix])
(cfg [:mapping :stop]))]
{:break? true})
(a.assoc
(state) :repl
(stdio.start
{:prompt-pattern (cfg [:prompt_pattern])
:cmd (cfg [:command])

:on-success
(fn []
(display-repl-status :started))

:on-error
(fn [err]
(display-repl-status err))

:on-exit
(fn [code signal]
(when (and (= :number (type code)) (> code 0))
(log.append [(.. comment-prefix "process exited with code " code)]))
(when (and (= :number (type signal)) (> signal 0))
(log.append [(.. comment-prefix "process exited with signal " signal)]))
(stop))

:on-stray-output
(fn [msg]
(log.append (format-msg msg)))}))))

(defn on-load []
(start))

(defn on-exit []
(stop))

(defn on-filetype []
(mapping.buf
:SndStart (cfg [:mapping :start])
start
{:desc "Start the REPL"})

(mapping.buf
:SndStop (cfg [:mapping :stop])
stop
{:desc "Stop the REPL"})

(mapping.buf
:SdnInterrupt (cfg [:mapping :interrupt])
interrupt
{:desc "Interrupt the REPL"}))
3 changes: 2 additions & 1 deletion fnl/conjure/config.fnl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
:hy :conjure.client.hy.stdio
:julia :conjure.client.julia.stdio
:racket :conjure.client.racket.stdio
:scheme :conjure.client.scheme.stdio
;;:scheme :conjure.client.scheme.stdio
:scheme :conjure.client.snd-s7.stdio
:lua :conjure.client.lua.neovim
:lisp :conjure.client.common-lisp.swank
:python :conjure.client.python.stdio
Expand Down
2 changes: 1 addition & 1 deletion lua/conjure/client/guile/socket.lua
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ local function parse_guile_result(s)
if s:find("scheme@%([%w%-%s]+%) %[%d+%]>") then
return {["done?"] = true, ["error?"] = true, result = nil}
else
return {result = s, ["error?"] = false, ["done?"] = false}
return {result = s, ["done?"] = false, ["error?"] = false}
end
end
end
Expand Down
Loading

0 comments on commit ad574db

Please sign in to comment.