<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Part-Time Dragon Slayer]]></title><description><![CDATA[I'm a DBA by day and a youth pastor by night. I love Perl.]]></description><link>https://blog.matthewdmiller.net</link><generator>RSS for Node</generator><lastBuildDate>Sun, 17 May 2026 00:04:39 GMT</lastBuildDate><atom:link href="https://blog.matthewdmiller.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Introduction to the Sam Text Editor]]></title><description><![CDATA[Programmers are passionate about their tools, and if there is one tool they are especially passionate about, it is their text editor. An editor war has raged between Emacs and vi for decades, and new challengers such as VS Code and Sublime Text vie f...]]></description><link>https://blog.matthewdmiller.net/introduction-to-the-sam-text-editor</link><guid isPermaLink="true">https://blog.matthewdmiller.net/introduction-to-the-sam-text-editor</guid><category><![CDATA[Text Editors]]></category><category><![CDATA[tools]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Fri, 24 Dec 2021 18:42:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1640371416044/q3hlK6fhU.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Programmers are passionate about their tools, and if there is one tool they are especially passionate about, it is their text editor. An <a target="_blank" href="https://en.wikipedia.org/wiki/Editor_war">editor war</a> has raged between Emacs and vi for decades, and new challengers such as VS Code and Sublime Text vie for superiority. I decided to try out an editor that isn't near as popular as these others but has no less a distinguished pedigree.</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Sam_%28text_editor%29">Sam</a> was one of two text editors included in the Plan 9 operating system. It was originally designed by Rob Pike for the Blit windowing terminal in the early 1980s.</p>
<p>Sam for modern Linux and BSD can be obtained from two different sources. One is <a target="_blank" href="https://9fans.github.io/plan9port/">Plan 9 from User Space</a> that ports Plan 9 programs to other Unix-like operating systems, and the other is <a target="_blank" href="https://github.com/deadpixi/sam">Deadpixi Sam</a> that has continued development of the 1990s Unix port of Sam. I installed and reviewed Deadpixi Sam. If you install a different version of Sam, some of the configuration details might differ, but most of the information here should apply to all versions of Sam.</p>
<h2 id="heading-a-brief-tutorial">A Brief Tutorial</h2>
<p>Vi is notorious for trapping novice programmers who don't even know how to exit it. I plead guilty here: The first time I was dropped into a vi session on an HP-UX server, I couldn't get it to do anything and was too afraid to ask someone thinking I had broken something. The learning curve for Sam isn't quite as steep, but it also isn't obvious what to do when you first launch Sam and are presented with this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640371405327/K0iReD2wV.png" alt="Sam on first launch" /></p>
<p>You could, of course, read the man page, but the man page being a reference source isn't really laid out in a way that introduces you to Sam. It starts out by detailing a whole bunch of editing commands you can't even use yet, because it's not clear how to even load a text file to edit. You have to read through over half of the man page before you get to that. Despite Sam being around since the 1980s, I couldn't find any quick tutorial to get you up and running in a couple minutes to experiment with Sam, so I'll try to do that here.</p>
<p>When you first launch Sam, it is divided into top and bottom areas or "windows." The top window is the command window. This is where you type commands to manipulate text and control Sam. The bottom is a text window. You start out with one text window, but you can open as many text windows as you want. The text windows display the contents of the files being edited.</p>
<p>Deadpixi Sam can be configured with a <code>.samrc</code> file in your home directory. I recommend copying the example that comes packaged with Deadpixi Sam in <code>doc/samrc</code> to <code>~/.samrc</code>, because it comes with some helpful defaults. To edit this file with Sam, you would load it by typing <code>B .samrc</code> in the command window followed by Enter. The cursor will change. Point at the text window. Select it to display the file by right clicking anywhere inside it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640371406981/JZtdsQ_iF.png" alt="Selecting a text window for current file" /></p>
<p>You can left click within the text window to move the text cursor around. You can left click and drag to select text or double click to select a word. If you double click just inside brackets, parentheses, quotes, etc., it will select all the text within the brackets. By default, you can navigate with the keyboard using Ctrl+e,x,d,s to move the text cursor up, down, right, and left. The reason I highly recommended copying over the <code>samrc</code> that comes with Deadpixi Sam is because it enables moving the text cursor with the arrow keys and the more familiar (at least to those coming from Vim) Ctrl+k,j,l,h. You can edit files directly in the text window.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640371408763/1SxCRy6e7.png" alt="Menu of commands to manipulate windows" /></p>
<p>Right click and hold (with most modern operating systems, we are used to right clicking and releasing to access context menus, but you have to keep the right mouse button held down to access the menu in Sam) to access a menu with commands to manipulate windows. Some of the commands give you a crosshairs cursor to select the size and position of windows. Below the window operators is a list of available files starting with <code>~~sam~~</code>, the command window. Selecting a file from the list makes the most recently used window on that file current. If no windows are open on the file, you are prompted to open one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640371410480/pc0uBKFQC.png" alt="Menu of editing commands" /></p>
<p>Middle click and hold (just like above but hold down on your mouse wheel) to access a menu with editing commands. With this menu you can do things like copy (called snarf in Sam for some reason), cut, and paste. If you copied the <code>samrc</code> over that comes with Deadpixi Sam, it binds the familiar Ctrl+x,c,v,q with cut, snarf, paste, and exchange.</p>
<p>Sam doesn't use the system clipboard, but you can swap Sam's snarf with the system with <code>&lt;exch&gt;</code> from the editing menu. This allows you to copy and paste into other apps and vice versa. By default, it swaps snarf with the system selection. In Linux, this is what pastes when you middle click. This didn't integrate with the clipboard manager I use, so I added a line to <code>.samrc</code> to tell Sam to use the system clipboard instead of the system selection.</p>
<pre><code>$
a/\n# Make <span class="hljs-keyword">work</span> <span class="hljs-keyword">with</span> <span class="hljs-keyword">system</span> clipboard manager\n/
a/snarfselection clipboard/
</code></pre><p>The dollar sign tells Sam to jump to the end of the file. The <code>a/text/</code> command appends text at the current location (there is also <code>i</code> to insert and <code>c</code> to replace). I did this to demonstrate some of the commands you can use in Sam, but for the above example, it probably would have been easier to type the above directly into the text window. You can also type regular expressions like <code>/font/</code> into the command window to locate strings in the text window. Consult the man file that comes with Sam for a complete list of available commands.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640371412167/KEY3LWmP0.png" alt="Appending option to Sam configuration file" /></p>
<p>Now we're ready to save our changes and exit Sam. Type <code>w</code> in the command window to write the changes to the file. Then type <code>q</code> to quit. If you type <code>q</code> when there are unsaved changes, instead of closing, Sam will print <code>?changed files</code>. To force it to close with unsaved changes, just type <code>q</code> a second time. If you copied the <code>samrc</code> over that comes with Deadpixi Sam, it binds the familiar Ctrl+s with write (and also Ctrl+z to undo).</p>
<h2 id="heading-review-of-sam">Review of Sam</h2>
<p>Sam does a lot of things different than the conventions used by most modern operating systems. For example, the scrollbar is on the left instead of the right. You can grab the scrollbar by left clicking and drag to scroll up and down, but moving your mouse up scrolls down, and moving your mouse down scrolls up. As mentioned in my review, you must hold down the right and middle mouse button to select from the menus (you can't just click and release). These would be fine if they followed the conventions of the operating system, but they will be the opposite of what most new users expect. This is because Sam is almost 40 years old and was created before many of these conventions were established.</p>
<p>It's obvious from projects like Plan 9 from User Space and posts on Hacker News and Reddit that Plan 9 still has a number of ardent followers. Sam is also reportedly the preferred editor of Ken Thompson, Bjarne Stroustrup, and Brian Kernighan. A project like Deadpixi has to tread a fine line between preserving Sam as it was to satisfy users who have built up muscle memory and modernizing it to attract new users. Copying the <code>samrc</code> over that comes with Deadpixi goes a long way toward configuring key bindings that make Sam mostly behave like other text entry in modern operating systems. What I still miss is being able to hold Shift while using the arrow keys to select text, and I don't think there's any way to do this just using <code>.samrc</code>. I made a couple additional tweaks to my <code>.samrc</code> during the couple of days I played around with Sam.</p>
<pre><code><span class="hljs-built_in">bind</span> * Home <span class="hljs-built_in">command</span> bol
<span class="hljs-built_in">bind</span> * End <span class="hljs-built_in">command</span> eol
</code></pre><p>This makes the Home and End key behave as you would expect. The maintainer of Deadpixi sets 12 pt. Go Regular as the font in the example, <code>samrc</code>; I changed this to 13 pt. Inconsolata. The Deadpixi example <code>samrc</code> also adds a list of background colors for new windows, but I decided to stick with just white. I set <code>tabs</code> to 2 spaces and the aforementioned <code>snarfselection</code> to <code>clipboard</code>.</p>
<p>Sam was created before desktop environments and window managers were common. The original Sam was designed to run on a terminal (not a terminal emulator like you have on your computer but an actual terminal). Instead of using more modern metaphors such as tabs, Sam includes its own rudimentary window management. You can have multiple text windows open and make Sam look something like this (the screenshot from the Deadpixi REAMDE):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640371413882/e402T0XMP.png" alt="Sam with multiple text windows open" /></p>
<p>The only way to create and position windows is using the mouse to sweep an area for the window. This is awkward, and during the couple of days I experimented with Sam, I primarily used the right-click menu to switch between which file occupied the single text window that was created upon launch. Key bindings for window tiling or even Acme-like tiling is listed as a development goal in the Deadpixi README but not yet implemented.</p>
<p>The Sam GUI is built with <a target="_blank" href="https://en.wikipedia.org/wiki/X_Toolkit_Intrinsics">Xt</a>, a library that provides primitives to create widgets for the X Window System used by widget toolkits like Motif (whereas GTK and Qt draw their own widgets). This gives it a decidedly dated look and feel. It's telling the the screenshots in Rob Pike's <a target="_blank" href="http://doc.cat-v.org/plan_9/4th_edition/papers/sam/">original 1987 paper</a> describing Sam look exactly like Sam does today. Removing the Xt dependency is listed as a stretch goal in the Deadpixi README, but continued development seems slow. At the time of this writing, it has been over a year since the last commit.</p>
<p>It also doesn't support other features most user's probably expect from a modern text editor. It doesn't do syntax highlighting, and that is listed under "Things That Won't Ever Happen (Sorry)" in the README. In a <a target="_blank" href="https://github.com/deadpixi/sam/issues/89">GitHub issue</a>, the maintainer clarifies it's not that he'll never implement syntax highlighting but just that it would be almost impossible in the current 30-year-old codebase. If he rewrites the GUI in Tcl to get rid of the Xt dependency, syntax highlighting might become a possibility.</p>
<p>While I enjoyed playing around with Sam for a couple of days, I don't see it becoming my main text editor. It was a nice peek at computing history, and I might keep it around to edit a configuration file now and again, but I'll continue using Geany when programming. The structural regular expressions and being able to pipe the current selection to a shell command and replace the selection with the result are neat but not compelling enough to do without things like syntax highlighting (plus most modern text editors can do those other things too).</p>
<p>Are you a Sam fan? Do you use it as your daily driver? I'd love to hear from you. How long have you used it? What is it about Sam that makes you prefer it to other text editors? Is there something I missed? Any tips or tricks to share?</p>
]]></content:encoded></item><item><title><![CDATA[Learn Common Lisp by Example: GTK GUI with SBCL]]></title><description><![CDATA[The cl-cffi-gtk library provides Common Lisp bindings to GTK. The library is developed with SBCL but should also work with Clozure CL and CLISP. For this tutorial, I'll be using SBCL. Instead of building yet another calculator, let's build a GUI for ...]]></description><link>https://blog.matthewdmiller.net/learn-common-lisp-by-example-gtk-gui-with-sbcl</link><guid isPermaLink="true">https://blog.matthewdmiller.net/learn-common-lisp-by-example-gtk-gui-with-sbcl</guid><category><![CDATA[Tutorial]]></category><category><![CDATA[GUI]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Sat, 20 Nov 2021 05:38:52 GMT</pubDate><content:encoded><![CDATA[<p>The cl-cffi-gtk library provides Common Lisp bindings to GTK. The library is developed with SBCL but should also work with Clozure CL and CLISP. For this tutorial, I'll be using SBCL. Instead of building yet another calculator, let's build a GUI for generating a tone.</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/clcffigtk.png?raw=true" alt="Screenshot" /></p>
<p>You'll need SBCL installed. It's available in the repositories of most Linux distros, so just install it from your distro's repo. Depending on your destkop environment, you probably already have GTK installed (even if you use KDE, it's highly likely you already have GTK installed). If you're on Windows or macOS, you'll probably have to install GTK in addition to SBCL.</p>
<p>The Common Lisp bindings to GTK can be installed with <a target="_blank" href="https://www.quicklisp.org/">Quicklisp</a>. If you don't already have Quicklisp installed, it's painless. See the Quicklisp website for more details, but here's an example of installing Quicklisp on Debian and configuring SBCL. The steps should be the same for any Linux distro and macOS.</p>
<pre><code class="lang-console">$ curl -O https://beta.quicklisp.org/quicklisp.lisp
$ sbcl --load quicklisp.lisp
&gt; (quicklisp-quickstart:install)
&gt; (ql:add-to-init-file)
</code></pre>
<p>The "proper" way to include a dependency would be to use <a target="_blank" href="https://common-lisp.net/project/asdf/">ASDF</a> and create a <code>.asd</code> file for the project. Since this is a quick tutorial, I'll use with <code>ql:quickload</code>.</p>
<pre><code class="lang-lisp">(ql:quickload :cl-cffi-gtk)
</code></pre>
<p>The first time you run <code>bleep.lisp</code>, it will take awhile as Quicklisp downloads cl-cffi-gtk (by default it will be downloaded to <code>~/quicklisp</code>).</p>
<pre><code class="lang-lisp">; Main window
(defvar window (make-instance 'gtk:gtk-window :type :toplevel :title "Bleep"))
(defvar vbox (make-instance 'gtk:gtk-box :orientation :vertical
                                                      :spacing 25
                                                      :margin 25))

(gtk:within-main-loop
  ; Quit program when window closed
  (gobject:g-signal-connect window "destroy" (lambda (widget)
    (declare (ignore widget))
    (gtk:leave-gtk-main)))
  ; Display GUI
  (gtk:gtk-container-add window vbox)
  (gtk:gtk-widget-show-all window))
</code></pre>
<p>Although written in C, GTK is object oriented. It uses a portable object system called GObject. GObject classes are wrapped with corresponding Lisp classes. You create a window by instantiating the <code>gtk:gtk-window</code> class.</p>
<p>The <code>gtk:gtk-box</code> is a packing widget. A <code>gtk:gtk-window</code> can only contain one widget at a time. Packing widgets are you used to pack widgets together and arrange them.</p>
<p>The <code>gtk:within-main-loop</code> macro does the work of setting up a GTK main loop. The macro does some additional bookkeeping to run the GUI in a separate thread. This is cool, because even after the window appears, you can still type commands into the REPL to interact with the program (e.g. query the properties of a widget). With most of the Lisp GUI libraries I've tried out, the GUI takes over completely once it is launched, and you have to close the window before being able to type commands into the REPL again.</p>
<p>Then add our packing widget to the window, and we're ready to launch our window. Now let's add some more widgets to it.</p>
<pre><code class="lang-lisp">(defvar slider (make-instance 'gtk:gtk-scale
                              :orientation :horizontal
                              :draw-value nil
                              :width-request 200
                              :adjustment
                              (make-instance 'gtk:gtk-adjustment
                                             :value 440
                                             :lower 20
                                             :upper 20000
                                             :step-increment 1)))
(gtk:gtk-box-pack-start vbox slider)
</code></pre>
<p>The range of frequencies audible by humans is typically between 20 Hz and 20 KHz (we lose the ability to hear some of those higher frequencies as we age). The <a target="_blank" href="https://en.wikipedia.org/wiki/A440_(pitch_standard">musical note A above middle C</a>&gt;) is 440 Hz. Since A4 serves as a general tuning standard, it seems like a sensible default, but if you run the above in SBCL, this is what you'll see:</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/clcffigtk-linearslider.png?raw=true" alt="Slider" /></p>
<p>The scale of 20 to 20,000 is so large that 440 doesn't appear to move the slider at all. Ideally, 440 would fall about the middle of the slider. To achieve this, let's use a logarithmic scale.</p>
<p>I found a <a target="_blank" href="https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249">Stack Overflow answer</a> on how to map a slider to a logarithmic scale. The code given in the answer is JavaScript, but it was easy enough to port to Common Lisp.</p>
<pre><code class="lang-lisp">; Scale used by slider
(defparameter *min-position* 0)
(defparameter *max-position* 2000)
; Range of frequencies
(defparameter *min-frequency* 20)
(defparameter *max-frequency* 20000)

; Logarithmic scale for frequency (so middle A [440] falls about in the middle)
; Adapted from https://stackoverflow.com/questions/846221/logarithmic-slider

(defvar min-freq (log *min-frequency*))
(defvar max-freq (log *max-frequency*))
(defvar frequency-scale (/ (- max-freq min-freq) (- *max-position* *min-position*)))
; Convert slider position to frequency
(defun position-&gt;frequency (position)
  (round (exp (+ min-freq (* frequency-scale (- position *min-position*))))))
; Convert frequency to slider position
(defun frequency-&gt;position (freq)
  (round (/ (- (log freq) min-freq) (+ frequency-scale *min-position*))))
</code></pre>
<p>I added some global parameters to the top of the script. The variable name <code>*min-position*</code> is just a Lisp naming convention for global parameters. I came up with the range of 0-2,000 by trial and error. It seemed to strike the best balance between each step of the slider making a noticeable change to the frequency while still allowing the user to narrow in on a specific frequency with just the slider.</p>
<p>Then we create two functions: one that takes the position on the slider and returns the frequency (<code>position-&gt;frequency</code>) and another that takes a frequency and returns the position on the slider (<code>frequency-position</code>). Now let's modify our slider to use <code>frequency-&gt;position</code> to convert the initial <code>value</code> to a slider position using our logarithmic scale.</p>
<pre><code class="lang-lisp">(defvar slider (make-instance 'gtk:gtk-scale
                              :orientation :horizontal
                              :draw-value nil
                              :adjustment
                              (make-instance 'gtk:gtk-adjustment
                                             :value (frequency-&gt;position 440)
                                             :lower *min-position*
                                             :upper *max-position*
                                             :step-increment 1)))
</code></pre>
<p>Underneath the slider is a spin button showing the current frequency and buttons to increase/decrease the frequency by one octave.</p>
<pre><code class="lang-lisp">; Create a spin button with a units label
; Arguments: from - number, lower bound of range),
;            to - number, upper bound of range
;            initial - number, initial value of spin button
;            units - string, label after spin button
; Optional Arguments: digits - number &lt;= 20, number of decimal places to show
; Return value: The gtk-spin-button instance inside the container
(defun units-spin-button (from to initial units &amp;key (digits 0))
  (let ((container (make-instance 'gtk:gtk-box :orientation :horizontal :spacing 10))
        (spin-button (make-instance 'gtk:gtk-spin-button
                                    :digits digits
                                    :adjustment
                                    (make-instance 'gtk:gtk-adjustment
                                                   :value initial
                                                   :lower from
                                                   :upper to
                                                   :step-increment 1)))
        (label (make-instance 'gtk:gtk-label :label units)))
    (gtk:gtk-box-pack-start container spin-button :fill nil)
    (gtk:gtk-box-pack-start container label :fill nil)
    ; Return the container holding the spin button and label
    spin-button))

(defvar frequency-field (units-spin-button *min-frequency* *max-frequency* 440 "Hz" :digits 2))

(defvar lower-button (make-instance 'gtk:gtk-button :label "&lt;"))
(defvar higher-button (make-instance 'gtk:gtk-button :label "&gt;"))

(defvar frequency-box (make-instance 'gtk:gtk-box :orientation :horizontal :spacing 25))
(gtk:gtk-box-pack-start frequency-box lower-button :fill nil)
(gtk:gtk-box-pack-start frequency-box (gtk:gtk-widget-parent frequency-field) :fill nil)
(gtk:gtk-box-pack-start frequency-box higher-button :fill nil)
(gtk:gtk-box-pack-start vbox frequency-box)
</code></pre>
<p>We can also use boxes to help with layout. I created a function that I can reuse later to generate the spin button and label and pack them together in a box.</p>
<p>At this point, we are starting to have a nice looking interface, but it doesn't do anything. If you click the buttons or slide the slider, nothing happens. Widgets emit signals, and callback functions can be connected to these signals. If we connect a callback function to the <code>change-value</code> signal of the slider, that function will be called whenever the slider is moved. The arguments a callback function takes are dependent on the signal being handled. The adjustment object of the spin button has a <code>value-changed</code> signal.</p>
<pre><code class="lang-lisp">; Link slider to text field display of frequency
(gobject:g-signal-connect slider "change-value"
  ; Connect to change-value signal of slider instead of value-changed signal of
  ; its corresponding adjustment object so that frequency will only be updated
  ; when interactively moved avoiding rounding differences between slider and
  ; sping button.
  (lambda (range scroll value)
    (declare (ignore range scroll))
    (setf (gtk:gtk-adjustment-value (gtk:gtk-spin-button-adjustment frequency-field))
          (position-&gt;frequency value))))
(gobject:g-signal-connect (gtk:gtk-spin-button-adjustment frequency-field) "value-changed"
  (lambda (adjustment)
    (setf (gtk:gtk-adjustment-value (gtk:gtk-range-adjustment slider))
          (frequency-&gt;position (gtk:gtk-adjustment-value adjustment)))))
</code></pre>
<p>Wire the buttons up to callback functions called <code>decrease-octave</code> and <code>increase-octave</code>. An <a target="_blank" href="https://en.wikipedia.org/wiki/Octave">octave</a> is "the interval between one musical pitch and another with double its frequency."</p>
<pre><code class="lang-lisp">; Buttons increase and decrease frequency by one octave
(defun set-frequency (freq)
  (setf (gtk:gtk-adjustment-value (gtk:gtk-spin-button-adjustment frequency-field)) freq))
(defun adjust-octave (modifier)
  (set-frequency (* (gtk:gtk-adjustment-value (gtk:gtk-spin-button-adjustment frequency-field)) modifier)))
(defun decrease-octave (widget) (declare (ignore widget)) (adjust-octave 0.5))
(defun increase-octave (widget) (declare (ignore widget)) (adjust-octave 2))

(gobject:g-signal-connect lower-button "clicked" #'decrease-octave)
(gobject:g-signal-connect higher-button "clicked" #'increase-octave)
</code></pre>
<p>We'll reuse the <code>units-spin-button</code> function we created to create a field to specify the duration of the beep in millseconds:</p>
<pre><code class="lang-lisp">(defvar control-box (make-instance 'gtk:gtk-box :orientation :horizontal :spacing 25))
(defvar duration-field (units-spin-button 1 600000 200 "ms"))
(gtk:gtk-box-pack-start control-box (gtk:gtk-widget-parent duration-field) :fill nil)
(gtk:gtk-box-pack-start vbox control-box)
</code></pre>
<p>Frequency is rather abstract. Let's also give the user the ability to select a musical note. We can store the corresponding frequencies for A4-G4 in an association list.</p>
<pre><code class="lang-lisp">; Notes -&gt; frequency (middle A-G [A4-G4])
; http://pages.mtu.edu/~suits/notefreqs.html
(defvar notes '(("A" . 440.00)
                ("B" . 493.88)
                ("C" . 261.63)
                ("D" . 293.66)
                ("E" . 329.63)
                ("F" . 349.23)
                ("G" . 292.00)))
</code></pre>
<p>We'll give the user a drop-down menu. Whenever a note is selected from the drop-down menu, we'll look up the frequency in the association list and set it using the <code>set-frequency</code> helper function we created for the octave buttons.</p>
<pre><code class="lang-lisp">; Create combo box and label
(defvar note-box (make-instance 'gtk:gtk-box :orientation :horizontal :spacing 10))
(defvar note-label (make-instance 'gtk:gtk-label :label "♪"))
(gtk:gtk-box-pack-start note-box note-label :fill nil)
(defvar note (make-instance 'gtk:gtk-combo-box-text))
(gtk:gtk-box-pack-start note-box note :fill nil)
; Populate combo box
(gtk:gtk-combo-box-text-append-text note "A")
(gtk:gtk-combo-box-text-append-text note "B")
(gtk:gtk-combo-box-text-append-text note "C")
(gtk:gtk-combo-box-text-append-text note "D")
(gtk:gtk-combo-box-text-append-text note "E")
(gtk:gtk-combo-box-text-append-text note "F")
(gtk:gtk-combo-box-text-append-text note "G")
; Set frequency to specific note
(gobject:g-signal-connect note "changed"
  (lambda (object)
    (let ((value (gtk:gtk-combo-box-text-get-active-text object)))
      (set-frequency (cdr (assoc value notes :test 'equal))))))
; Pack the combo box
(gtk:gtk-box-pack-start control-box note-box :fill nil)
(gtk:gtk-box-pack-start vbox control-box)
</code></pre>
<p>Finally, let's make some noise.</p>
<pre><code class="lang-lisp">(ql:quickload :cl-portaudio)

; Generate a tone using CL-PortAudio
(defun generate-tone (frequency duration)
  (let ((frames-per-buffer 1024)
        (sample-rate 44100d0)
        (amplitude 0.5))
    ; Initialize PortAudio environment
    (portaudio:with-audio
      ; Open and start audio stream
      (portaudio:with-default-audio-stream (astream 1 1
                                            :sample-format :float
                                            :sample-rate sample-rate
                                            :frames-per-buffer frames-per-buffer)
        (dotimes (i (round (/ (* (/ duration 1000) sample-rate) frames-per-buffer)))
          ; Write buffer to output stream
          (portaudio:write-stream astream
            ; portaudio:write-stream requires an array as input, not a list
            (make-array frames-per-buffer :element-type 'single-float :initial-contents
              (loop for j from (+ (* frames-per-buffer i) 1) to (* frames-per-buffer (+ i 1)) collect
                (let ((time (/ j sample-rate)))
                  ; Since sample-rate and pi are double-float, they make result
                  ; double-float. PortAudio expects single-float, and will warn
                  ; when run with SBCL if not given single-float.
                  (coerce (* amplitude (sin (* 2 pi frequency time))) 'single-float))))))))))
</code></pre>
<p>We'll use <a target="_blank" href="https://github.com/filonenko-mikhail/cl-portaudio">Common Lisp bindings to PortAudio</a> to generate the tone. This can be loaded with <a target="_blank" href="https://www.quicklisp.org/">Quicklisp</a>.</p>
<p>CL-PortAudio comes with a couple of helpful macros that makes initializing PortAudio and starting a stream simple. The <code>with-audio</code> macro executes body within a PortAudio initialize/terminate environment. The <code>with-default-audio-stream</code> macro executes body with an opened and started stream and shuts down the stream after it is done.</p>
<p>Then you just feed PortAudio arrays of samples, <code>:frames-per-buffer</code> at a time. I initiated <code>with-default-audio-stream</code> with one channel, so the array is just a single-dimensional array of floating point numbers. If you were producing stereo sound, you would generate a two-dimensional array. The <a target="_blank" href="http://pld.cs.luc.edu/telecom/mnotes/digitized_sound.html">basic formula for a sine wave</a> is A sin(2πft) where <em>A</em> is amplitude, <em>f</em> is frequency, and <em>t</em> is time:</p>
<pre><code class="lang-lisp">(* amplitude (sin (* 2 pi frequency time)))
</code></pre>
<p>Wire this up to a button between the duration and note selector, and you're ready to make some noise.</p>
<pre><code class="lang-lisp">(defvar play-button (make-instance 'gtk:gtk-button :label "Play"))
(gobject:g-signal-connect play-button "clicked" (lambda (widget)
  (declare (ignore widget))
  (generate-tone (gtk:gtk-adjustment-value (gtk:gtk-spin-button-adjustment frequency-field))
                 (gtk:gtk-adjustment-value (gtk:gtk-spin-button-adjustment duration-field)))))
(gtk:gtk-box-pack-start control-box play-button :fill nil)
</code></pre>
<p><em>You can check out the entire example on <a target="_blank" href="https://github.com/goober99/lisp-gui-examples">GitHub</a>. This started as a personal learning project to explore the state of GUI programming in Lisp and has become a series of tutorials on building GUIs with various dialects of Lisp.</em></p>
]]></content:encoded></item><item><title><![CDATA[Learn Scheme by Example: Tk GUI with Chicken Scheme]]></title><description><![CDATA[PS/Tk stands for a portable Scheme interface to the Tk GUI toolkit. It has a rich history going all the way back to Scheme_wish by Sven Hartrumpf in 1997. Wolf-Dieter Busch created a Chicken port called Chicken/Tk in 2004. It took on its current name...]]></description><link>https://blog.matthewdmiller.net/learn-scheme-by-example-tk-gui-with-chicken-scheme</link><guid isPermaLink="true">https://blog.matthewdmiller.net/learn-scheme-by-example-tk-gui-with-chicken-scheme</guid><category><![CDATA[GUI]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Fri, 12 Nov 2021 21:51:55 GMT</pubDate><content:encoded><![CDATA[<p>PS/Tk stands for a portable Scheme interface to the Tk GUI toolkit. It has a rich history going all the way back to Scheme_wish by Sven Hartrumpf in 1997. Wolf-Dieter Busch created a Chicken port called Chicken/Tk in 2004. It took on its current name when Nils M Holm stripped it of Chicken-isms to make it portable amongst Scheme implementations in 2006.</p>
<p>If you've ever tried to write portable Scheme, you know that, except for the most trivial of programs, it is much easier said than done. Holm's <code>pstk.scm</code> had a configurable section titled <code>NON-PORTABLE</code> that you had to configure for your chosen implementation. It came full circle and was repackaged as a Chicken egg.</p>
<p>Chicken is a popular Scheme implementation that compiles Scheme to C. Eggs are Chicken-specific extenstion libraries that are stored in a centralized repository (like CPAN but for Chicken Scheme). Instead of building yet another calculator, let's build a GUI for generating a tone.</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/pstk.png?raw=true" alt="Screenshot" /></p>
<p>You'll need Chicken installed. It's available in the repositories of most Linux distros. PS/Tk interfaces with Tk, not with C library bindings, but with a named pipe to <code>tclsh8.6</code>. The TCL package in most Linux distros will provide this. For Debian, I did <code>sudo apt install chicken-bin tcl tk</code>. Once Chicken is installed, you can use the <code>chicken-install</code> utility that comes with it to install the PS/Tk egg.</p>
<pre><code class="lang-console">$ chicken-install -sudo pstk
</code></pre>
<p>When you think of Tk, you may think of something that looks like this:</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/tk-old.png?raw=true" alt="Screenshot" /></p>
<p>Tk has come a long way in recent years. Tcl/Tk 8.5 and later comes with a new set of widgets built in called Tile or Ttk that can be themed. These widgets are available alongside the classic widgets, so you have to explicitly tell your app to use Ttk or else it will end up looking like it was designed for a 1980s Unix workstation.</p>
<pre><code class="lang-scheme">(import pstk)

(tk-start)
(ttk-map-widgets 'all) ; Use the Ttk widget set

(tk/wm 'title tk "Bleep")

(tk-event-loop)
</code></pre>
<p>All PS/Tk function names begin with <code>tk/</code> or <code>tk-</code> (or <code>ttk/</code> and <code>ttk-</code> for the few Ttk-specific functions). The <a target="_blank" href="https://github.com/utz82/pstk/tree/master/doc">doc directory</a> in the PS/Tk GitHub repo unfortunately has not been updated since this convention was adopted. One example from the docs is <code>start-tk</code> which is now <code>tk-start</code>.</p>
<p>The <code>ttk-map-widgets</code> function is what tells Tk to use the Ttk widgets instead of the classic widgets. Tk comes with a few built-in themes. The default themes on Windows and macOS supposedly do a decent job of approximating the look of native widgets on those platforms. I don't use either of those platforms, so I can't verify this first hand. For some reason, the default theme on Linux is vaguely Windows 95ish. It comes with a built-in theme called <a target="_blank" href="https://wiki.tcl-lang.org/page/ttk%3A%3Atheme%3A%3Aclam">clam</a> that is supposed to provide "a look somewhat like a Linux application". You can set this theme with <code>(ttk/set-theme "clam")</code>, but it's really not that much of an improvement.</p>
<p>Ideally, something like <a target="_blank" href="https://github.com/Geballin/gtkTtk">gtkTtk</a> that has GTK do the actual drawing would be integrated into Tcl/Tk and become the default on Linux. In the meantime, there are <a target="_blank" href="https://ttkthemes.readthedocs.io/en/latest/themes.html">third party themes</a> that imitate the look and feel of the most popular GTK and Qt themes. I use MATE with the Arc GTK theme, so I went with the Arc theme. There was even a Debian package for it (<code>sudo apt install tcl-ttkthemes</code>). We can then <a target="_blank" href="https://blog.serindu.com/2019/03/07/applying-tk-themes-to-git-gui/">apply the theme system wide</a> (<code>echo '*TkTheme: arc' | xrdb -merge -</code>), so that all Tk apps such as git-gui also inherit the theme. It is probably better to give your Linux users instructions on how to install their own theme instead of hard coding one with <code>ttk/set-theme</code>, so they can choose one that matches their system theme (KDE users might pick Breeze while Ubuntu users might opt for Yaru). The screenshots in this tutorial use the Arc theme.</p>
<p>We set the window title with <code>tk/wm</code> and start the event loop with <code>tk-event-loop</code>. We now have an empty window. Now let's add some widgets to this window.</p>
<pre><code class="lang-scheme">(define slider (tk 'create-widget 'scale 'from: 20 'to: 20000))
(slider 'set 440)
(tk/grid slider 'row: 0 'columnspan: 3 'sticky: 'ew 'padx: 20 'pady: 20)
</code></pre>
<p>Widgets are organized hierarchically. This is done by invoking a parent widget with the sub-command <code>create-widget</code>. PS/Tk associates a widget named <code>tk</code> with the top-level window, so most widgets will start as a call to <code>tk</code> (e.g. <code>(tk 'create-widget 'label 'text: "Hello, World!")</code>). Options are quoted and get a trailing colon (e.g. <code>'text: "Hello, World!"</code>).</p>
<p>Creating a widget returns a Scheme function. If you give this function a name, you can call it with sub-commands such as <code>configure</code>, <code>get</code>, and <code>set</code>. Just creating a widget doesn't make it appear on screen. For that you need a geometry manager, of which Tk has three: the packer, the gridder, and the placer (<code>tk/pack</code>, <code>tk/grid</code>, and <code>tk/place</code> in Scheme, respectively).</p>
<p>The range of frequencies audible by humans is typically between 20 Hz and 20 KHz (we lose the ability to hear some of those higher frequencies as we age). The <a target="_blank" href="https://en.wikipedia.org/wiki/A440_(pitch_standard">musical note A above middle C</a>&gt;) is 440 Hz. Since A4 serves as a general tuning standard, it seems like a sensible default, but if you run the above in Chicken, this is what you'll see:</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/pstk-linearslider.png?raw=true" alt="Slider" /></p>
<p>The scale of 20 to 20,000 is so large that 440 doesn't appear to move the slider at all. Ideally, 440 would fall about the middle of the slider. To achieve this, let's use a logarithmic scale.</p>
<p>I found a <a target="_blank" href="https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249">Stack Overflow answer</a> on how to map a slider to a logarithmic scale. The code given in the answer is JavaScript, but it was easy enough to port to Scheme.</p>
<pre><code class="lang-scheme">; Scale used by slider
(define *min-position* 0)
(define *max-position* 2000)
; Range of frequencies
(define *min-frequency* 20)
(define *max-frequency* 20000)

; Logarithmic scale for frequency (so middle A [440] falls about in the middle)
; Adapted from https://stackoverflow.com/questions/846221/logarithmic-slider

(define min-freq (log *min-frequency*))
(define max-freq (log *max-frequency*))
(define frequency-scale (/ (- max-freq min-freq) (- *max-position* *min-position*)))
; Convert slider position to frequency
(define (position-&gt;frequency position)
  (round (exp (+ min-freq (* frequency-scale (- position *min-position*))))))
; Convert frequency to slider position
(define (frequency-&gt;position freq)
  (round (/ (- (log freq) min-freq) (+ frequency-scale *min-position*))))
</code></pre>
<p>I added some global parameters to the top of the script. The variable name <code>*min-position*</code> is just a Lisp naming convention for global parameters. I came up with the range of 0-2,000 by trial and error. It seemed to strike the best balance between each step of the slider making a noticeable change to the frequency while still allowing the user to narrow in on a specific frequency with just the slider.</p>
<p>Then we create two functions: one that takes the position on the slider and returns the frequency (<code>position-&gt;frequency</code>) and another that takes a frequency and returns the position on the slider (<code>frequency-position</code>). Now let's set the initial position of our slider with the <code>frequency-&gt;position</code> function:</p>
<pre><code class="lang-scheme">(define slider (tk 'create-widget 'scale 'from: *min-position* 'to: *max-position*))
(slider 'configure 'value: (frequency-&gt;position 440))
</code></pre>
<p>Underneath the slider is a spin box showing the current frequency and buttons to increase/decrease the frequency by one octave.</p>
<pre><code class="lang-scheme">; Create a spin box with a units label
; Returns frame widget encompassing both spin box and label and the spin box
; widget itself. This way you can access the value of the spin box.
; e.g. (define-values (box-with-label just-box) (units-spinbox 1 12 6 "inches"))
(define (units-spinbox from to initial units)
  (let* ((container (tk 'create-widget 'frame))
         (spinbox (container 'create-widget 'spinbox 'from: from 'to: to
                             'width: (+ 4 (string-length (number-&gt;string to)))))
         (label (container 'create-widget 'label 'text: units)))
    (spinbox 'set initial)
    (tk/pack spinbox label 'side: 'left 'padx: 2)
    (values container spinbox)))

(define lower-button (tk 'create-widget 'button 'text: "&lt;"))
(define-values (frequency-ext frequency-int)
  (units-spinbox *min-frequency* *max-frequency* 440 "Hz"))
(define higher-button (tk 'create-widget 'button 'text: "&gt;"))

(tk/grid lower-button 'row: 1 'column: 0 'padx: 20 'pady: 20)
(tk/grid frequency-ext 'row: 1 'column: 1 'padx: 20 'pady: 20)
(tk/grid higher-button 'row: 1 'column: 2 'padx: 20 'pady: 20)
</code></pre>
<p>The frame widget is an invisible widget that helps with layout. Since all I need to arrange within the frame is a spin box and a label, I used <code>tk/pack</code> to <code>pack</code> them side by side. The frame is then organized in a <code>grid</code> with the rest of the widgets. I created a function that I can reuse later to generate the spin box, label, and frame all together. At this point, we are starting to have a nice looking interface, but it doesn't do anything. If you click the buttons or slide the slider, nothing happens. The widgets have a <code>command</code> option that wires the widget up to a function. If we add a command to the slider, that command will be called each time the slider is moved.</p>
<pre><code class="lang-scheme">(define slider (tk 'create-widget 'scale 'from: *min-position* 'to: *max-position*
                   'command: (lambda (x) (frequency-int 'set (position-&gt;frequency x)))))
</code></pre>
<p>The command for the slider takes one argument that indicates the new value of the slider. The spin box does have a <code>command</code> option, but the command is only called when the value is changed by clicking the up or down arrow, not when the value is changed by other means such as typing a frequency into the field. Tk has a <code>bind</code> command (the Scheme <code>tk/bind</code> function) that allows binding functions to an event on a widget. We'll bind our callback to the <code>KeyRelase</code> event. The <code>tk/bind</code> function takes up to three arguments. The first is the widget to bind to (or a tag created with <code>tk/bindtags</code> to apply the binding to multiple widgets). The second is the event pattern. The event pattern is surrounded by angle brackets and can specify modifiers, event types, and more. You can find detailed documentation on the event pattern in the <a target="_blank" href="https://www.tcl.tk/man/tcl8.6/TkCmd/bind.htm">Tcl/Tk documentation</a>. The third is a lambda expression to associate with the event.</p>
<pre><code class="lang-scheme">(tk/bind frequency-int '&lt;KeyRelease&gt; (lambda ()
  ; If frequency value is a valid number, set slider to current value
  (let ((numified (string-&gt;number (frequency-int 'get))))
    (when numified
      (slider 'configure 'value: (frequency-&gt;position numified))))))
</code></pre>
<p>Wire the buttons up to callback functions called <code>decrease-octave</code> and <code>increase-octave</code>. An <a target="_blank" href="https://en.wikipedia.org/wiki/Octave">octave</a> is "the interval between one musical pitch and another with double its frequency."</p>
<pre><code class="lang-scheme">; Set frequency slider and display
(define (set-frequency freq)
  (when (and (&gt;= freq *min-frequency*) (&lt;= freq *max-frequency*))
    (slider 'configure 'value: (frequency-&gt;position freq))
    (frequency-int 'set freq)))

; Buttons increase and decrease frequency by one octave
(define (adjust-octave modifier)
  (set-frequency (* (string-&gt;number (frequency-int 'get)) modifier)))
(define (decrease-octave) (adjust-octave 0.5))
(define (increase-octave) (adjust-octave 2))
</code></pre>
<p>If you slide the slider, the text field updates accordingly. If you type a number in the text field, the slider updates accordingly. All good, right? What if a user (and you know they will) enters a number higher than 20,000 or a letter?</p>
<p>Let's extend the function that returns our labeled spin box to bind a validation function to the <code>FocusOut</code> event on the spin box. The spin box does have a <code>validatecommand</code> option, but I wasn't able to get it working. I looked through the examples that have come with the various variations of PS/Tk and couldn't find a single example of a spin box with a <code>validatecommand</code>. I even looked at the source code for <a target="_blank" href="https://github.com/bintracker/bintracker/">Bintracker</a>, a chiptune audio workstation written in Chicken Scheme with a PS/Tk GUI and developed by the current maintainer of the PS/Tk egg. Even it binds a <code>validate-new-value</code> function to the <code>Return</code> and <code>FocusOut</code> events of the spin box rather than using <code>validatecommand</code>.</p>
<pre><code class="lang-scheme">; Create a spin box with a units label
; Returns frame widget encompassing both spin box and label and the spin box
; widget itself. This way you can access the value of the spin box.
; e.g. (define-values (box-with-label just-box) (units-spinbox 1 12 6 "inches"))
(define (units-spinbox from to initial units)
  (let* ((container (tk 'create-widget 'frame))
         (spinbox (container 'create-widget 'spinbox 'from: from 'to: to
                             'width: (+ 4 (string-length (number-&gt;string to)))))
         (label (container 'create-widget 'label 'text: units)))
    (spinbox 'set initial)
    (tk/bind spinbox '&lt;FocusOut&gt; (lambda ()
      (let ((current-value (string-&gt;number (spinbox 'get))))
        (unless (and current-value
                     (&gt;= current-value from)
                     (&lt;= current-value to))
          (spinbox 'set from)
          ; Also reset slider position to make sure it still matches display
          (slider 'configure 'value: (frequency-&gt;position (string-&gt;number (frequency-int 'get))))))))
    (tk/pack spinbox label 'side: 'left 'padx: 2)
    (values container spinbox)))
</code></pre>
<p>We'll also use this function to create a field to specify the duration of the beep in milliseconds:</p>
<pre><code class="lang-scheme">(define-values (duration-ext duration-int) (units-spinbox 1 600000 200 "ms"))
(tk/grid duration-ext 'row: 2 'column: 0 'padx: 20 'pady: 20)
</code></pre>
<p>Frequency is rather abstract. Let's also give the user the ability to select a musical note. We can store the corresponding frequencies for A4-G4 in an association list.</p>
<pre><code class="lang-scheme">; Notes -&gt; frequency (middle A-G [A4-G4])
; http://pages.mtu.edu/~suits/notefreqs.html
(define notes '(("A" 440.00)
                ("B" 493.88)
                ("C" 261.63)
                ("D" 293.66)
                ("E" 329.63)
                ("F" 349.23)
                ("G" 292.00)))
</code></pre>
<p>We'll give the user a drop-down menu. Whenever a note is selected from the drop-down menu, we'll look up the frequency in the association list and set it using the <code>set-frequency</code> helper function we created for the octave buttons.</p>
<pre><code class="lang-scheme">(define note-frame (tk 'create-widget 'frame))
(define note (note-frame 'create-widget 'combobox 'width: 2 'values: '("A" "B" "C" "D" "E" "F" "G")))
(tk/bind note '&lt;&lt;ComboboxSelected&gt;&gt; (lambda () (set-frequency (cadr (assoc (note 'get) notes)))))
(define note-label (note-frame 'create-widget 'label 'text: "♪"))
(tk/pack note-label note 'side: 'left 'padx: 2)
(tk/grid note-frame 'row: 2 'column: 2 'padx: 20 'pady: 20)
</code></pre>
<p>Now, let's make some noise. There are Chicken Scheme <a target="_blank" href="http://wiki.call-cc.org/eggref/5/allegro">bindings</a> to the <a target="_blank" href="https://en.wikipedia.org/wiki/Allegro_(software_library">Allegro</a>&gt;) library. Allegro is a library primarily used by games for cross-platform graphics, input devices, and more. What we're interested in is the audio addon that can be used to generate a tone with a sine wave. You'll need to install the Allegro library. Make sure you also install the header files. In some Linux distros, these are split into a separate package (e.g. <code>liballegro5-dev</code> on Debian). Also, install the Allegro egg (<code>chicken-install -sudo allegro</code>). I added the following lines near the top to import the Allegro bindings (and the chicken memory module, which we'll also use) and initialize Allegro.</p>
<pre><code class="lang-scheme">(import (prefix allegro "al:"))
(import (chicken memory))

(define +pi+ 3.141592)

; Initialize Allegro and audio addon
(unless (al:init) (print "Could not initialize Allegro."))
(unless (al:audio-addon-install) (print "Could not initialize sound."))
(al:reserve-samples 0)
</code></pre>
<p>The Allegro egg is accompanied by a couple of examples but no examples showing the use of the audio addon. The Allegro library itself comes with an <a target="_blank" href="https://github.com/liballeg/allegro5/blob/master/examples/ex_saw.c">example showing how to generate a saw wave</a>, but being a C library, the example is, of course, in C. I <a target="_blank" href="https://github.com/goober99/lisp-gui-examples/blob/master/examples/pstk/saw.scm">ported that example to Scheme</a>. I would have contributed the example back to the Allegro egg, but the repo is marked as "archived by the owner" and read-only on GitHub. I've included the example in the repo alongside the rest of the code for this tutorial in case someone finds it useful.</p>
<p>Allegro is very low-level. You create an audio <code>stream</code>. In this case, the stream buffers eight fragments of 1,024 samples each at a frequency (often called sampling rate) of 44,100 Hz (the sampling rate of an audio CD), which means there are 44,100 samples per second. Each sample is a 32-bit float (what is called the bit depth of the audio), and we only have one channel to keep things as simple as possible.</p>
<pre><code class="lang-scheme">; Generate a tone using Allegro
(define (generate-tone frequency duration)
  (let* ((samples-per-buffer 1024)
         (stream-frequency 44100)
         (amplitude 0.5)
         (stream (al:make-audio-stream 8 samples-per-buffer stream-frequency 'float32 'one))
         (queue (al:make-event-queue))
         (event (al:make-event)))

    (unless (al:audio-stream-attach-to-mixer! stream (al:default-mixer))
      (print "Could not attach stream to mixer."))
    (al:event-queue-register-source! queue (al:audio-stream-event-source stream))

    (let event-loop ((n 0))
      ; Grab and handle events
      (when (and (&lt; n (/ (* (/ duration 1000) stream-frequency) samples-per-buffer))
                 (al:event-queue-wait! queue event))
        (case (al:event-type event) ('audio-stream-fragment
          (let ((buffer (al:audio-stream-fragment stream)))
            ; If the stream is not ready for new data, buffer will be null.
            (if (not buffer) (event-loop n) (begin
              (fill-buffer buffer n) ; Placeholder
              ; Repeat
              (event-loop (+ n 1)))))))))

    (al:audio-stream-drain stream)))
</code></pre>
<p>An event loop waits for the audio stream to ask for another buffer. Our job is to fill that buffer with 1,024 32-bit floats at a time. In the code listing above, this is done by <code>fill-buffer</code>. That was just a placeholder, so I could break the code up into shorter, more easily explainable chunks. This is what goes in the place of <code>(fill-buffer buffer n)</code>:</p>
<pre><code class="lang-scheme">(let ((adr (pointer-&gt;address buffer)))
  (let loop ((i 0))
    (when (&lt; i samples-per-buffer)
      (let ((time (/ (+ (* samples-per-buffer n) i) stream-frequency)))
        ; al:audio-stream-fragment returns a C pointer. Use (chicken
        ; memory) module to operate on foreign pointer objects.
        ; Iterate over array four bytes at a time since 32-bit depth.
        (pointer-f32-set! (address-&gt;pointer (+ adr (* i 4)))
          (* amplitude (sin (* 2 +pi+ frequency time))))
        (loop (+ i 1)))))
  (unless (al:audio-stream-fragment-set! stream buffer)
    (print "Error setting stream fragment")))
</code></pre>
<p>The Allegro egg is a pretty thin wrapper of the Allegro library. The <code>audio-stream-fragment</code> procedure in the egg just passes along the C pointer that the corresponding <code>al_get_audio_stream_fragment</code> function from the C library returns. It would have been nice if the egg had offered some Scheme conveniences atop Allegro like allowing us to pass a Scheme list or array to Allegro to provide the buffer of samples. Since it doesn't, we'll use the chicken memory module to fill the C array starting at the C pointer returned by <code>audio-stream-fragment</code>. We use <code>pointer-&gt;address</code> to get the address of the pointer. A pointer refrences a byte of memory. We can reference the preceding or following byte by subtracting or adding 1 to the address. Since we are filling the array with 32-bit floats, and 32 bits is 4 bytes, we want to increment the address by 4 each time. Then we can set the value of the current location with pointer-f32-set!.</p>
<p>Then you just need to feed Allegro buffers of 1,024 samples at a time. The <a target="_blank" href="http://pld.cs.luc.edu/telecom/mnotes/digitized_sound.html">basic formula for a sine wave</a> is A sin(2πft) where <em>A</em> is amplitude, <em>f</em> is frequency, and <em>t</em> is time.</p>
<pre><code class="lang-scheme">(* amplitude (sin (* 2 +pi+ frequency time)))
</code></pre>
<p>Wire this up to a play button, and you're ready to make some noise.</p>
<pre><code class="lang-scheme">(define play-button (tk 'create-widget 'button 'text: "Play" 'command: (lambda ()
  (generate-tone (string-&gt;number (frequency-int 'get)) (string-&gt;number (duration-int 'get))))))
(tk/grid play-button 'row: 2 'column: 1 'padx: 20 'pady: 20)
</code></pre>
<p>Tk has been around a long time, and it shows. While it is stable and highly portable, even with recent improvements, it just looks a little dated. At least on Linux, none of the themes I tried really fit in. There were always differences that made the Tk GUI stick out like a sore thumb. If you're building an internal tool where it doesn't really matter how pretty it is, you can get Tk to work with a variety of Schemes in a variety of places.</p>
<p><em>You can check out the entire example on <a target="_blank" href="https://github.com/goober99/lisp-gui-examples">GitHub</a>. This started as a personal learning project to explore the state of GUI programming in Lisp and has become a series of tutorials on building GUIs with various dialects of Lisp.</em></p>
]]></content:encoded></item><item><title><![CDATA[Learn Common Lisp by Example: Qt GUI with EQL5]]></title><description><![CDATA[Embedded Qt5 Lisp (EQL5) is a Qt5 binding for Embedded Common Lisp (ECL). EQL5 is a bit different than most bindings. Instead of executing your Lisp source with ecl and importing the bindings, you compile a new interpreter (eql5) that combines both E...]]></description><link>https://blog.matthewdmiller.net/learn-common-lisp-by-example-qt-gui-with-eql5</link><guid isPermaLink="true">https://blog.matthewdmiller.net/learn-common-lisp-by-example-qt-gui-with-eql5</guid><category><![CDATA[GUI]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Fri, 19 Feb 2021 20:36:48 GMT</pubDate><content:encoded><![CDATA[<p>Embedded Qt5 Lisp (EQL5) is a Qt5 binding for Embedded Common Lisp (ECL). EQL5 is a bit different than most bindings. Instead of executing your Lisp source with <code>ecl</code> and importing the bindings, you compile a new interpreter (<code>eql5</code>) that combines both ECL and Qt5 bindings. Instead of building yet another calculator, let's build a GUI for generating a tone.</p>
<p>There are ports of EQL5 to Android and iOS, and a work-in-progress port to Sailfish OS, so EQL5 can also be used to develop mobile apps. The "Embedded" part of the name (of both ECL and EQL5) refers to the fact that it can be embedded in existing C++ projects. For this tutorial, we'll be building a standalone desktop app.</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/eql5.png?raw=true" alt="Screenshot" /></p>
<h2 id="compiling-eql5">Compiling EQL5</h2>
<p>EQL5 doesn't appear to be in the repos of any major Linux distro. It is available from AUR on Arch, but since I use Debian, I compiled it from source. Don't worry. It's not as scary as it sounds.</p>
<ul>
<li>Clone the EQL5 Git repo. EQL5 doesn't appear to have releases or tags, so I guess you just clone <code>master</code> and hope that it's in a workable state.</li>
</ul>
<pre><code class="lang-console">$ git clone https://gitlab.com/eql/EQL5.git
</code></pre>
<ul>
<li>Install dependencies. This was actually the hardest part. Not the installing. That's just <code>apt install whatever</code> (or the package manager of your preferred distro). There are hundreds of Qt packages on Debian, and it's not always clear what Qt module corresponds to what Debian package (here's a <a target="_blank" href="https://askubuntu.com/a/577334">list</a> I found useful). If I got an unknown module error during the <code>make</code> step, I would look the Qt module up in the list on Ask Ubuntu and install the corresponding dev package. I ended up needing to install libqt5svg5-dev, qml-module-qtquick2, qtbase5-dev, qtdeclarative5-dev, qtmultimedia5-dev, qttools5-dev, and qtwebengine5-dev. This will get EQL5 compiled, but if you choose to build your GUI with QML, depending on what <code>import</code> statements you use in your QML file, you'll need some additional packages. To follow this tutorial, you'll also need qml-module-qtquick-controls2, qml-module-qtquick-layouts, qml-module-qtquick-window2. The other dependency you'll need is ECL, and I also recommend installing <code>qml</code> (it is helpful if building your GUI with QML). You can install all the dependencies needed on Debian/Ubuntu with:</li>
</ul>
<pre><code class="lang-console">$ sudo apt install ecl libqt5svg5-dev qml-module-qtquick2 qtbase5-dev qtdeclarative5-dev qtmultimedia5-dev qttools5-dev qtwebengine5-dev qml-module-qtquick-controls2 qml-module-qtquick-layouts qml-module-qtquick-window2 qml
</code></pre>
<ul>
<li>Navigate into the <code>src</code> subdirectory of the cloned EQL5 Git repo, compile, and install. The <code>-qt5</code> flag was necessary on Debian, because <code>qmake</code> is a symlink to <code>qtchooser</code>. On other distros, this flag may not be required.</li>
</ul>
<pre><code class="lang-console">$ cd EQL5/src
$ ecl -shell make
$ qmake -qt5 eql5.pro
$ make
$ sudo make install
</code></pre>
<ul>
<li>Now <code>eql5</code> should be available to run. Verify it with <code>eql5 -qgui</code>, which will launch a GUI REPL. This also gives you access to some documentation on the EQL5 functions. Go the the <em>Help</em> tab for a searchable list of functions.</li>
</ul>
<h2 id="building-the-gui-with-qml">Building the GUI with QML</h2>
<p>EQL5 supports both Qt Widgets and Qt Quick. They primarily differ in how you define your UI. With Qt Widgets, you declare it procedurally. With Qt Quick, you use a declarative language called QML to define your UI. The underlying implementation of the widgets also differ. Qt Widgets has been around a lot longer and has a broader range of available widgets, but many of these widgets are more desktop-oriented without touch components and not easily adapted for touch. Qt Quick, on the other hand, has been developed from the beginning to work well on touch screens (tablets, smartphones, etc.).</p>
<p>Qt is essentially maintaining two sets of widgets. It would make more sense to me if QML was just an alternative way of specifying which widgets to use instead of a completely new set of widgets, but I'm not a Qt maintainer or even a C++ developer. I guess creating new widgets was easier than adapting the old widgets to be touch friendly.</p>
<p>Qt Quick is sometimes criticized for having a foreign look on the desktop (neither Qt Quick or Qt Widgets use native widgets, but Qt Widgets look more native on the desktop). It also has a smaller set of available widgets. Native look and feel is not important to me, and Qt Quick has plenty of widgets to implement the example in this tutorial. Given a choice between defining a GUI procedurally and declaratively, I'm going to choose the declarative option.</p>
<p>The syntax of QML looks like a cross between JSON and CSS. Objects are specified followed by a pair of braces. Properties of the object are specified with key-value colon-separated pairs. You can create white text on a blue background like this:</p>
<pre><code class="lang-qml">import QtQuick 2.0

Rectangle {
  width: 200
  height: 100
  color: "blue"

  Text {
    anchors.centerIn: parent
    color: "white"
    text: "Hello, world!"
  }
}
</code></pre>
<p>You can build custom GUI elements out of rectangles and other drawing primitives, but it would be nice to have some pre-defined widgets to use. Let's also import Qt Quick Controls and Qt Quick Layouts. You will need to have both modules installed on your system. They are probably available in your distro's package manager (see above for installing them on Debian).</p>
<pre><code class="lang-qml">import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.2
</code></pre>
<p>For maximum compatibility, I recommend specifying the minimum version of modules. You might have Qt Quick Controls 2.15 on the machine your developing on, but one of your users might have an earlier version. Only bump the version if a later version has features you need to use. For example, <a target="_blank" href="https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html#margins-attached-prop"><code>Layout.margins</code></a> wasn't introduced until Qt Quick Layouts 1.2. We'll be setting margins in the example we're building with this tutorial, so I imported version 1.2 of Qt Quick Layouts.</p>
<p>We arrange items in our UI using <code>ColumnLayout</code> and <code>RowLayout</code> from Qt Quick Layouts. <code>ColumnLayout</code> arranges its children vertically, and <code>RowLayout</code> arranged its children horizontally. At the top, there will be a slider, so we'll put a <code>Slider</code> within a <code>ColumnLayout</code>.</p>
<pre><code class="lang-qml">ColumnLayout {
  id: root

  Slider {
    id: frequencySlider
    from: 20
    value: 440
    to: 20000
    Layout.fillWidth: true
    Layout.margins: 25
  }
}
</code></pre>
<p>The range of frequencies audible by humans is typically between 20 Hz and 20 KHz (we lose the ability to hear some of those higher frequencies as we age). The <a target="_blank" href="https://en.wikipedia.org/wiki/A440_(pitch_standard">musical note A above middle C</a>&gt;) is 440 Hz. Since A4 serves as a general tuning standard, it seems like a sensible default. <code>Layout.fillWidth</code> makes the slider take up the full width of the window.</p>
<p>Under the slider, there will be a row (a great use for <code>RowLayout</code>) with two buttons and a spin box (a widget for entering a number within a fixed range).</p>
<pre><code class="lang-qml">RowLayout {
  spacing: 25
  Layout.alignment: Qt.AlignHCenter
  Layout.margins: 25

  Button {
    text: "&lt;"
  }

  RowLayout {
    SpinBox {
      id: frequencyField
      editable: true
      from: 20
      value: frequencySlider.value
      to: 20000
    }
    Label { text: "Hz" }
  }

  Button {
    text: "&gt;"
  }
}
</code></pre>
<p>Under that is another row of controls: another spin box, a button, and a drop-down menu to select notes from. Frequency is rather abstract. The drop-down gives the user the ability to select a musical note.</p>
<pre><code class="lang-qml">RowLayout {
  spacing: 25
  Layout.margins: 25

  RowLayout {
    SpinBox {
      id: durationField
      editable:true
      from: 1
      value: 200
      to: 600000
    }
    Label { text: "ms" }
  }

  Button {
    text: "Play"
  }

  RowLayout {
    Label { text: "♪" }
    ComboBox {
      model: ["A", "B", "C", "D", "E", "F", "G"]
    }
  }
}
</code></pre>
<p>I started this project with zero knowledge of QML. I went from Googling "qml" to the complete mockup above in about 30 minutes. I haven't written any of the application logic (in fact, we haven't even touched Common Lisp yet), but you can see how powerful a declarative syntax like QML is for defining GUIs. On big teams, you could even have a designer write the QML while a backend programmer wrote the logic. If you installed the QML viewer above (the qml package on Debian), you can preview your GUI with:</p>
<pre><code class="lang-console">qml bleep.qml
</code></pre>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/eql5-mockup.png?raw=true" alt="Screenshot" /></p>
<h2 id="writing-the-logic-in-common-lisp">Writing the Logic in Common Lisp</h2>
<p>Copy <code>qml-lisp.lisp</code> from the EQL5 example directory (<code>EQL5/examples/M-modules/quick/qml-lisp/qml-lisp.lisp</code>) to your working directory. This enables QML to call Lisp functions and vice versa. I'm not sure why this isn't built into EQL5, but it's easy enough to copy it from the Qt Quick examples that come with EQL5. Also, create a <code>bleep.lisp</code> for the program logic.</p>
<pre><code class="lang-lisp">(qrequire :quick) ; Have EQL5 use Qt Quick module from Qt
(require :qml-lisp "qml-lisp") ; Load qml-lisp.lisp package copied from example
(use-package :qml) ; Import all external symbols from above package
</code></pre>
<p>The <code>qrequire</code> function is part of the EQL5 bindings. It loads a specified Qt module. In our case, we want to load the Qt Quick module. Then we load the Lisp package we copied from the EQL5 examples that enables communication between Lisp and QML. We'll use these two imports to run the QML UI we created above.</p>
<pre><code class="lang-lisp">(defun run ()
  ; QQuickView provides a window for displaying a Qt Quick user interface:
  ; https://doc.qt.io/qt-5/qquickview.html
  (setf qml:*quick-view* (qnew "QQuickView"))
  (x:do-with qml:*quick-view*
    (|setSource| (|fromLocalFile.QUrl| "bleep.qml"))
    (|setTitle| "Bleep")
    (|show|)))

(run)
</code></pre>
<p>The <code>*quick-view*</code> variable is supplied by the <code>qml-lisp.lisp</code> file we copied over (hence the <code>qml</code> namespace). It can be either a QQuickView or QQuickWidget Qt object. We use <code>qnew</code> from EQL5 to create a <a target="_blank" href="https://doc.qt.io/qt-5/qquickview.html">QQuickView</a> object. The <code>qnew</code> function creates a Qt object of a given class.</p>
<p>The <code>x</code> namespace includes utility functions and macros that come with EQL5. Since this namespace is built into EQL5, I would have thought the <code>qml</code> namespace could have been too. The <code>x</code> namespace does not appear to be documented anywhere. I copied the usage of <code>do-with</code> from the Qt Quick examples that come with EQL5. It basically let's us chain together a bunch of Qt methods on the <code>*quick-view*</code> object.</p>
<p>EQL5 comes with <code>qfun</code> for calling Qt methods on objects. For example, <code>(qfun qml:*quick-view* "show")</code> would call the <code>show</code> method on the <code>qml:*quick-view*</code> object. EQL5 also comes with a shorthand for this: <code>(|show| qml:*quick-view*)</code>. We can use this shorthand to set the source of the QQuickView to the QML file we created above, set a title for the window, and finally call the <code>show</code> method to display the window. Execute this with <code>eql5</code>, and you should get a window that looks just like the window you previewed above with <code>qml</code>.</p>
<pre><code class="lang-console">$ eql5 bleep.lisp
</code></pre>
<p>You can tell that the default style has been designed to be touch friendly. The handle on the slider is extra big so that it can be dragged with a finger. All the buttons have plenty of padding to make them easy targets. Qt Quick also comes with a platform-agnostic style called Fusion that offers a desktop-oriented look and feel.</p>
<p>There are <a target="_blank" href="https://doc.qt.io/QT-5/qtquickcontrols2-styles.html#using-styles-in-qt-quick-controls">four ways</a> to set the style. The first is using the <code>QQuickStyle</code> class, but this class is not wrapped by EQL5. The second is to pass a <code>-style</code> command line argument. Asking our user to include a command line argument to get the desired styling seems a bit much. The next option is to set a <code>QT_QUICK_CONTROLS_STYLE</code> environment variable. ECL has <a target="_blank" href="https://common-lisp.net/project/ecl/static/manual/Operating-System-Interface.html"><code>ext:setenv</code></a> for setting environment variables. We'll set the environment variable before defining <code>run</code> and then execute our code again:</p>
<pre><code class="lang-lisp">; Use the desktop-oriented style Fusion instead of the default
; https://doc.qt.io/QT-5/qtquickcontrols2-styles.html
; EQL5 doesn't wrap the QQuickStyle class so using environment variable
(ext:setenv "QT_QUICK_CONTROLS_STYLE" "fusion")
</code></pre>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/eql5-fusion.png?raw=true" alt="Screenshot" /></p>
<p>The scale of 20 to 20,000 is so large that 440 barely appears to move the slider at all. Ideally, 440 would fall about the middle of the slider. To achieve this, let's use a logarithmic scale.</p>
<p>I found a <a target="_blank" href="https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249">Stack Overflow answer</a> on how to map a slider to a logarithmic scale. The code given in the answer is JavaScript. We can embed JavaScript directly into our QML, so we could use the JavaScript example. This being a Lisp tutorial, we are going to port it to Common Lisp.</p>
<pre><code class="lang-lisp">; Scale used by slider
(defparameter *min-position* 0)
(defparameter *max-position* 2000)
; Range of frequencies
(defparameter *min-frequency* 20)
(defparameter *max-frequency* 20000)

; Logarithmic scale for frequency (so middle A [440] falls about in the middle)
; Adapted from https://stackoverflow.com/questions/846221/logarithmic-slider

(defvar min-freq (log *min-frequency*))
(defvar max-freq (log *max-frequency*))
(defvar frequency-scale (/ (- max-freq min-freq) (- *max-position* *min-position*)))
; Convert slider position to frequency
(defun position-&gt;frequency (position)
  (round (exp (+ min-freq (* frequency-scale (- position *min-position*))))))
; Convert frequency to slider position
(defun frequency-&gt;position (freq)
  (round (/ (- (log freq) min-freq) (+ frequency-scale *min-position*))))
</code></pre>
<p>I added some global parameters to the top of the script. The variable name <code>*min-position*</code> is just a Lisp naming convention for global parameters. I came up with the range of 0-2,000 by trial and error. It seemed to strike the best balance between each step of the slider making a noticeable change to the frequency while still allowing the user to narrow in on a specific frequency with just the slider. Then we create two functions: one that takes the position on the slider and returns the frequency (<code>position-&gt;frequency</code>) and another that takes a frequency and returns the position on the slider (<code>frequency-position</code>).</p>
<p>It would be useful if these global parameters were available both to Lisp and QML. Qt has <a target="_blank" href="https://doc.qt.io/qt-5/qtqml-cppintegration-contextproperties.html">a way to embed C++ Objects into QML</a> by setting a context property on the root context. We could pass the string "Bugs Bunny" from C++ to QML this way:</p>
<pre><code class="lang-cpp"><span class="hljs-comment">// C++</span>
QString fictionalRabbit = <span class="hljs-string">"Bugs Bunny"</span>;
view.rootContext()-&gt;setContextProperty(<span class="hljs-string">"fictionalRabbit"</span>, fictionalRabbit);
</code></pre>
<pre><code class="lang-qml">// QML
Text { text: fictionalRabbit }
</code></pre>
<p>Using EQL5 and Lisp, it would look like this:</p>
<pre><code class="lang-lisp">(|setContextProperty| (|rootContext| qml:*quick-view*)
  "fictionalRabbit" (qvariant-from-value "Bugs Bunny" "QString"))
</code></pre>
<p>The order is reversed in Lisp compared to C++. Whereas in C++ you have <code>view.rootContext()</code>, in Lisp you do <code>(|rootContext| qml:*quick-view*)</code>. The method to call comes first. Then the object to call that method on followed by any additional arguments. The value passed must be a C++ object. EQL5 comes with <code>qvariant-from-value</code> that makes it easy to construct a <code>QVariant</code> of a specified type. That's more than I want to type for every variable I want to export from Lisp into QML, so I whipped up a little helper function:</p>
<pre><code class="lang-lisp">; Helper function to make Lisp data available in QML
; Allows writing (set-context-property variable-in-lisp "variableInLisp" "QString")
; instead of (|setContextProperty| (|rootContext| qml:*quick-view*)
;   "variableInLisp" (qvariant-from-value variable-in-lisp "QString"))
(defun set-context-property (lisp-var qml-name type-name)
  (let ((root-context (|rootContext| qml:*quick-view*))
        (objectified (qvariant-from-value lisp-var type-name)))
    (|setContextProperty| root-context qml-name objectified)))
</code></pre>
<p>Then I added this to my <code>run</code> function:</p>
<pre><code class="lang-lisp">; Make data available in QML
(set-context-property *min-position* "minPosition" "int")
(set-context-property *max-position* "maxPosition" "int")
(set-context-property *min-frequency* "minFrequency" "int")
(set-context-property *max-frequency* "maxFrequency" "int")
</code></pre>
<p>We now need to modify our QML to use these Lisp functions and variables. The first thing we need to do is add another <code>import</code> statement at the top.</p>
<pre><code class="lang-qml">import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.2
import EQL5 1.0
</code></pre>
<p>This imports everything we need to call Lisp functions from QML.</p>
<p>If you played around with the QML mockup above, you may have noticed moving the slider automatically updated the spin box underneath it. This was done with a property binding. The value of the spin box was set to <code>frequencySlider.value</code>. Whenever the slider value changes, the spin box value automatically updates. This was fine for a quick mockup, but we'd like for it to work both ways. When you change the value of the spin box, the slider should also automatically update. Unfortunately, QML doesn't support <a target="_blank" href="http://imaginativethinking.ca/bi-directional-data-binding-qt-quick/">bi-directional property bindings</a>. What we'll do is create a property that we'll bind both the slider and spin box to. Then we'll create handlers in both to update this property.</p>
<pre><code class="lang-qml">ColumnLayout {
  id: root

  property real frequency: 440

  Slider {
    id: frequencySlider
    from: minPosition
    value: Lisp.call("frequency-&gt;position", root.frequency)
    to: maxPosition
    onValueChanged: root.frequency = Lisp.call("position-&gt;frequency", value)
    Layout.fillWidth: true
    Layout.margins: 25
  }

...

    RowLayout {
      SpinBox {
        id: frequencyField
        editable: true
        from: minFrequency
        value: root.frequency
        to: maxFrequency
      }
      Label { text: "Hz" }
    }
...
}
</code></pre>
<p>The range for the slider and spin box is now defined using the context properties set in Lisp. To call Lisp functions, use <code>Lisp.call()</code>. It's not pretty (the function name must be quoted and the list comma separated), but it gets the job done. If you run the code with EQL5 from a terminal, you can move the slider, and the spin box will update accordingly, but you'll get a whole bunch of these warnings in your terminal:</p>
<pre><code>QML Slider: Binding <span class="hljs-keyword">loop</span> detected <span class="hljs-keyword">for</span> property "value"
</code></pre><p>Whenever you move the slider, <code>onValueChanged</code> updates the <code>frequency</code> property. When <code>frequency</code> changes this triggers another update of the slider, which in turn, updates <code>frequency</code> again, creating a loop. Qt Quick Controls 2.2 and later have <code>onMoved</code> in addition to <code>onValueChanged</code>. If you swap <code>onValueChanged</code> out for <code>onMoved</code>, it breaks the loop. With <code>onMoved</code>, the slider only updates the <code>frequency</code> property when interactively moved. When a change to <code>frequency</code> triggers a value change of the slider, it will not be propogated back to <code>frequency</code> avoiding the binding loop.</p>
<p>The other problem with our quick QML mockup upon closer inspection is that the QML spin box only works on integers. We want more precision than that to represent notes. For example, middle C is 261.63. Qt Widgets has <a target="_blank" href="https://doc.qt.io/qt-5/qdoublespinbox.html"><code>QDoubleSpinBox</code></a>, but Qt Quick doesn't have an <a target="_blank" href="https://bugreports.qt.io/browse/QTBUG-67349">equivalent</a>.</p>
<p>There is an <a target="_blank" href="https://doc.qt.io/qt-5/qml-qtquick-controls2-spinbox.html#custom-values">example</a> in the Qt documentation of the QML SpinBox on how it can be customized to accept floating point numbers. The example as-is truncates digits after 2 decimal places, thus 500.157 would become 500.15. This is probably contrary to what users expect, so I added <code>Math.round</code> to <code>value</code> and <code>valueFromText</code>.</p>
<pre><code class="lang-qml">SpinBox {
  id: frequencyField
  editable: true
  from: minFrequency * 100
  value: Math.round(root.frequency * 100)
  to: maxFrequency * 100
  stepSize: 100
  onValueChanged: root.frequency = value / 100

  property int decimals: 2
  property real realValue: value / 100

  validator: DoubleValidator {
    bottom: Math.min(frequencyField.from, frequencyField.to)
    top: Math.max(frequencyField.from, frequencyField.to)
  }

  textFromValue: function(value, locale) {
    return Number(value / 100).toLocaleString(locale, 'f', decimals)
  }

  valueFromText: function(text, locale) {
    return Math.round(Number.fromLocaleString(locale, text) * 100)
  }
}
</code></pre>
<p>On either side of the spin box underneath the slider are buttons to increase/decrease the frequency by one octave. This could be done with a little JavaScript right in the QML, but since this is a Lisp tutorial, we're going to do it with Common Lisp. You can access QML properties from Lisp, but it needs <code>objectName</code> to be set. To have uniform access to QML items from both QML and Lisp, it is convenient to set both <code>id</code> and <code>objectName</code> to the same name.</p>
<pre><code class="lang-qml">ColumnLayout {
  id: root
  objectName: "root"

  property real frequency: 440

  ...
}
</code></pre>
<p>Note the double quotes around the <code>objectName</code>. It can't be a bare keyword. It must be a string. We can then access properties of this item from Lisp with <code>q&lt;</code> and <code>q&gt;</code> (both from <code>qml-lisp.lisp</code> that we copied over.) They are shorthands for <code>qml-get</code> and <code>qml-set</code>, respectively.</p>
<pre><code class="lang-lisp">; Buttons increase and decrease frequency by one octave
(defun adjust-octave (modifier)
  (let* ((freq (q&lt; |frequency| "root"))
         (new-freq (* freq modifier)))
    (unless (or (&lt; new-freq *min-frequency*) (&gt; new-freq *max-frequency*))
      (q&gt; |frequency| "root" new-freq))))
(defun decrease-octave () (adjust-octave 0.5))
(defun increase-octave () (adjust-octave 2))
</code></pre>
<p>Wire the QML buttons up to these functions. An <a target="_blank" href="https://en.wikipedia.org/wiki/Octave">octave</a> is "the interval between one musical pitch and another with double its frequency."</p>
<pre><code class="lang-qml">Button {
  text: "&lt;"
  onClicked: Lisp.call("decrease-octave")
}

...

Button {
  text: "&gt;"
  onClicked: Lisp.call("increase-octave")
}
</code></pre>
<p>We gave the user a drop-down menu (combo box) in our QML mockup. Whenever a note is selected from the drop-down menu, we'll look up the frequency in a model and update the <code>frequency</code> property.</p>
<pre><code class="lang-qml">ComboBox {
  textRole: "note"
  // Notes -&gt; frequency (middle A-G [A4-G4])
  // http://pages.mtu.edu/~suits/notefreqs.html
  model: [
    { note: "A", freq: 440.00 },
    { note: "B", freq: 493.88 },
    { note: "C", freq: 261.63 },
    { note: "D", freq: 293.66 },
    { note: "E", freq: 329.63 },
    { note: "F", freq: 349.23 },
    { note: "G", freq: 392.00 }
  ]
  onActivated: root.frequency = model[index]["freq"]
}
</code></pre>
<p>I also had to add <code>(si::trap-fpe t nil)</code> to the top of my Lisp file. If not, I got a <code>Condition of type: DIVISION-BY-ZERO</code> error whenever trying to expand the combo box. I'm not sure exactly why. I just copied it from one of the Qt Quick examples bundled with EQL5. There were no comments or documentation explaining its purpose.</p>
<p>Now, let's make some noise.</p>
<pre><code class="lang-lisp">(ql:quickload "cl-portaudio") ; Use Quicklisp to load CL-PortAudio

; Generate a tone using CL-PortAudio
(defun generate-tone (frequency duration)
  (let ((frames-per-buffer 1024)
        (sample-rate 44100d0)
        (amplitude 0.5))
    ; Initialize PortAudio environment
    (portaudio:with-audio
      ; Open and start audio stream
      (portaudio:with-default-audio-stream (astream 1 1
                                            :sample-format :float
                                            :sample-rate sample-rate
                                            :frames-per-buffer frames-per-buffer)
        (dotimes (i (round (/ (* (/ duration 1000) sample-rate) frames-per-buffer)))
          ; Write buffer to output stream
          (portaudio:write-stream astream
            ; portaudio:write-stream requires an array as input, not a list
            (make-array frames-per-buffer :initial-contents
              (loop for j from (+ (* frames-per-buffer i) 1) to (* frames-per-buffer (+ i 1)) collect
                (let ((time (/ j sample-rate)))
                  (* amplitude (sin (* 2 pi frequency time))))))))))))
</code></pre>
<p>We'll use <a target="_blank" href="https://github.com/filonenko-mikhail/cl-portaudio">Common Lisp bindings to PortAudio</a> to generate the tone. This can be installed with <a target="_blank" href="https://www.quicklisp.org/">Quicklisp</a>. If you don't already have Quicklisp installed, it's painless. See the Quicklisp website for more details, but here's an example of installing Quicklisp on Debian and configuring ECL. The steps should be the same for any Linux distro and macOS.</p>
<pre><code class="lang-console">$ curl -O https://beta.quicklisp.org/quicklisp.lisp
$ ecl -load quicklisp.lisp
&gt; (quicklisp-quickstart:install)
&gt; (ql:add-to-init-file)
</code></pre>
<p>The first time you run <code>bleep.lisp</code>, it will take awhile as Quicklisp downloads CL-PortAudio (by default it will be downloaded to <code>~/quicklisp</code>). The "proper" way to include this dependency would be to use <a target="_blank" href="https://common-lisp.net/project/asdf/">ASDF</a> and create a <code>.asd</code> file for the project. EQL5 includes <a target="_blank" href="https://gitlab.com/eql/EQL5/-/tree/master/my_app">an example</a> of how to package an EQL5 app with ASDF. Since this is a quick tutorial, I'll stick with <code>ql:quickload</code>.</p>
<p>CL-PortAudio comes with a couple of helpful macros that makes initializing PortAudio and starting a stream simple. The <code>with-audio</code> macro executes body within a PortAudio initialize/terminate environment. The <code>with-default-audio-stream</code> macro executes body with an opened and started stream and shuts down the stream after it is done.</p>
<p>Then you just feed PortAudio arrays of samples, <code>:frames-per-buffer</code> at a time. I initiated <code>with-default-audio-stream</code> with one channel, so the array is just a single-dimensional array of floating point numbers. If you were producing stereo sound, you would generate a two-dimensional array. The <a target="_blank" href="http://pld.cs.luc.edu/telecom/mnotes/digitized_sound.html">basic formula for a sine wave</a> is A sin(2πft) where <em>A</em> is amplitude, <em>f</em> is frequency, and <em>t</em> is time:</p>
<pre><code class="lang-lisp">(* amplitude (sin (* 2 pi frequency time)))
</code></pre>
<p>Wire this up to the play button in the QML, and you're ready to make some noise.</p>
<pre><code class="lang-qml">Button {
  text: "Play"
  onClicked: Lisp.call("generate-tone", frequency, durationField.value)
}
</code></pre>
<p><em>You can check out the entire example on <a target="_blank" href="https://github.com/goober99/lisp-gui-examples">GitHub</a>. This started as a personal learning project to explore the state of GUI programming in Lisp and has become a series of tutorials on building GUIs with various dialects of Lisp.</em></p>
]]></content:encoded></item><item><title><![CDATA[Learn Clojure by Example: JavaFX GUI with Cljfx]]></title><description><![CDATA[Clojure is a dialect of Lisp that runs on the JVM. JavaFX is a modern GUI
toolkit for the JVM. You could use JavaFX directly with Clojure's Java interop,
but Cljfx provides a declarative and functional wrapper for JavaFX. Instead of
building yet anot...]]></description><link>https://blog.matthewdmiller.net/learn-clojure-by-example-javafx-gui-with-cljfx</link><guid isPermaLink="true">https://blog.matthewdmiller.net/learn-clojure-by-example-javafx-gui-with-cljfx</guid><category><![CDATA[Clojure]]></category><category><![CDATA[GUI]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Mon, 11 Jan 2021 01:01:22 GMT</pubDate><content:encoded><![CDATA[<p>Clojure is a dialect of Lisp that runs on the JVM. JavaFX is a modern GUI
toolkit for the JVM. You could use JavaFX directly with Clojure's Java interop,
but Cljfx provides a declarative and functional wrapper for JavaFX. Instead of
building yet another calculator, we're going to use Cljfx to build a GUI for
generating a tone.</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/cljfx.png" alt="Screenshot" /></p>
<p>You'll need Clojure installed. We also need a way to pull the Cljfx dependency
into our app. It seems <a target="_blank" href="https://clojure.org/guides/deps_and_cli">deps.edn</a>
would be the easiest way to accomplish this for a short tutorial example such
as this, but I develop on Debian and found that the new <a target="_blank" href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=891141">command line
tools</a> for Clojure
that enable this haven't made it into Debian yet. I could install Clojure from
the Clojure website, but the point of this tutorial is to be easy to follow by
someone not familiar with Clojure. It's a lot easier to direct a person to <code>apt
install clojure</code> (or whatever package manager your preferred distro uses). This
tutorial is a living document maintained on GitHub along with the example code.
Whenever the Clojure command line tools become available on Debian, it's
possible I'll revisit this tutorial and update it.</p>
<p>The Clojure build tool Leiningen is capable of managing dependencies (and a
whole lot more). There is also a build tool for Clojure called Boot. I found
more plentiful tutorials and beginner resources for Leiningen, plus Leiningen
is available as a Debian package, so for this tutorial, Leiningen it is.
Install Clojure and Leiningen from your distro's repo. Debian also has an
OpenJFX package, but Leiningen was able to pull OpenJFX in as a dependency of
Cljfx. The version pulled in by Leiningen is probably more up to date than
whatever might be sitting in your distro's repos.</p>
<p>After that, we need to create a Leiningen project directory. This can be
accomplished with <code>lein new app bleep</code>, but that created a directory full of
subdirectories and files that were unnecessary for a short little example like
this. I created the directory structure (<code>mkdir -p cljfx/src/bleep</code>) and
created <code>cljfx/project.clj</code> and <code>cljfx/src/bleep/core.clj</code> with the minimum
needed to create a window with Cljfx.</p>
<p><code>project.clj</code></p>
<pre><code class="lang-clojure">(defproject bleep "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [cljfx "1.7.12"]
                 [com.jsyn/jsyn "20170815"]]
  :main bleep.core)
</code></pre>
<p><code>core.clj</code></p>
<pre><code class="lang-clojure">(ns bleep.core
  (:gen-class)
  (:require [cljfx.api :as fx])
  (:import [javafx.application Platform]
           [com.jsyn JSyn]
           [com.jsyn.unitgen LineOut SineOscillator]))

(defn hello-world [&amp; args]
  {:fx/type :label
   :text "Hello, World!"})

(defn root [&amp; args]
  {:fx/type :stage
   :showing true
   :title "Bleep"
   :scene {:fx/type :scene
           :root {:fx/type :v-box
                  :padding 25
                  :spacing 40
                  :children [{:fx/type hello-world}]}}})

(def renderer
  (fx/create-renderer))

(defn -main [&amp; args]
  (Platform/setImplicitExit true)
  (renderer {:fx/type root}))
</code></pre>
<p>The project file (<code>project.clj</code>) is the file that tells Leiningen about your
project (such as its dependencies). Typically with Leiningen, your code will
live in the <code>src</code> subdirectory in a subdirectory that matches the top-level
namespace of your project. All this can be changed with your <code>project.clj</code>, but
we'll be sticking to convention for this example. In this subdirectory is
<code>core.clj</code>.</p>
<p>Begin the file with a namespace declaration. The namespace should have a
<code>(:gen-class)</code> declaration in the <code>ns</code> form at the top for Leiningen. Since
we'll be using Cljfx to create our GUI, we need to <code>require</code> it. We'll mostly
be using JavaFX via Cljfx, but you can also access JavaFX classes directly.
Let's <code>import</code> (a way to get Java code into Clojure) the JavaFX Platform class.
We'll also import the Java JSyn library for use later in generating the tone.</p>
<p>Leiningen needs a <code>-main</code> function (note the leading dash is part of the
function name). This is the function that will get called when you run your app
with Leiningen or when you compile it to a standalone JAR. We use the
<code>setImplicitExit</code> method from the JavaFX Platform class to make sure the JavaFX
runtime shuts down when the window is closed.</p>
<p>Cljfx is declarative instead of imperative or object oriented like many GUI
libraries. You describe the layout with a map of key-value pairs instead of
creating controls with methods or functions. The <code>:fx/type</code> key has a value of
a kebab-cased keyword derived from a JavaFX class name. The other keys of the
map are the kebab-cased properties of that class. You can refer to the <a target="_blank" href="https://openjfx.io/">JavaFX
documentation</a> for a list of classes and their properties.
JavaFX is well documented and has a large number of controls available.</p>
<p>JavaFX defines the user interface by means of a stage and a scene. The stage is
the top-level JavaFX container (the window). The scene is the container for all
content. To add a JavaFX class to the map, you convert the class name to
kebab-case. For example, JavaFX has a <code>VBox</code> pane used to lay out controls
vertically. This would be written <code>:v-box</code> in the Cljfx map. The <code>VBox</code> class
has a <code>padding</code> property. We can set this to 25 by adding a <code>:padding</code> key to
the map with a value of 25.</p>
<p>Cljfx provides a renderer function created with <code>fx/create-renderer</code> that you
pass the map describing your user interface to. You can call <code>renderer</code>
multiple times to dynamically change the GUI. Now let's replace the Hello World
label with a slider:</p>
<pre><code class="lang-clojure">(defn frequency-slider [{:keys [frequency]}]
  {:fx/type :slider
   :min 20
   :max 20000
   :value frequency})
</code></pre>
<p>Instead of placing the definition of your entire UI into one big map, you can
compose the UI from reusable functions. This also makes your code more
readable, because you don't have a deeply nested map. These functions can be
used just like any other JavaFX class. The <code>:fx/type</code> key is the function name,
and the other keys of the map are the arguments to the function. We can add the
<code>frequency-slider</code> we created above to the <code>:children</code> vector of the <code>:v-box</code>
in the <code>root</code> map like this:</p>
<pre><code class="lang-clojure">[{:fx/type frequency-slider
  :frequency 440}]
</code></pre>
<p>The range of frequencies audible by humans is typically between 20 Hz and 20
KHz (we lose the ability to hear some of those higher frequencies as we age).
The <a target="_blank" href="https://en.wikipedia.org/wiki/A440_(pitch_standard">musical note A above middle
C</a>) is 440 Hz. Since A4
serves as a general tuning standard, it seems like a sensible default, but if
you run the above with <code>lein run</code>, this is what you'll see:</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/cljfx-linearslider.png" alt="Slider" /></p>
<p>The scale of 20 to 20,000 is so large that 440 doesn't appear to move the
slider at all. Ideally, 440 would fall about the middle of the slider. To
achieve this, let's use a logarithmic scale.</p>
<p>I found a <a target="_blank" href="https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249">Stack Overflow
answer</a>
on how to map a slider to a logarithmic scale. The code given in the answer is
JavaScript, but it was easy enough to port to Clojure.</p>
<pre><code class="lang-clojure">; Scale used by slider
(def min-position 0)
(def max-position 2000)
; Range of frequencies
(def min-frequency 20)
(def max-frequency 20000)

; Logarithmic scale for frequency (so middle A [440] falls about in the middle)
; Adapted from https://stackoverflow.com/questions/846221/logarithmic-slider

(def min-freq (Math/log min-frequency))
(def max-freq (Math/log max-frequency))
(def frequency-scale (/ (- max-freq min-freq) (- max-position min-position)))
; Convert slider position to frequency
(defn position-&gt;frequency [position]
  (int (Math/round (Math/exp (+ min-freq (* frequency-scale (- position min-position)))))))
; Convert frequency to slider position
(defn frequency-&gt;position [freq]
  (int (Math/round (/ (- (Math/log freq) min-freq) (+ frequency-scale min-position)))))
</code></pre>
<p>I added some global parameters to the top of the script. I came up with the
range of 0-2,000 by trial and error. It seemed to strike the best balance
between each step of the slider making a noticeable change to the frequency
while still allowing the user to narrow in on a specific frequency with just
the slider.</p>
<p>Then we create two functions: one that takes the position on the slider and
returns the frequency (<code>position-&gt;frequency</code>) and another that takes a
frequency and returns the position on the slider (<code>frequency-position</code>). Now
let's set the initial position of our slider with the <code>frequency-&gt;position</code>
function:</p>
<pre><code class="lang-clojure">(defn frequency-slider [{:keys [frequency]}]
  {:fx/type :slider
   :min min-position
   :max max-position
   :value (frequency-&gt;position frequency)})
</code></pre>
<p>Underneath the slider is a text field showing the current frequency.</p>
<pre><code class="lang-clojure">(defn frequency-controls [{:keys [frequency]}]
  {:fx/type :h-box
   :alignment :center
   :spacing 20
   :children [{:fx/type :h-box
               :alignment :center
               :spacing 5
               :children [{:fx/type :text-field
                           :text (str frequency)}
                          {:fx/type :label
                           :text "Hz"}]}]})
</code></pre>
<p>Add this to the <code>:children</code> vector of the <code>:v-box</code> in the <code>root</code> map:</p>
<pre><code class="lang-clojure">[{:fx/type frequency-slider
  :frequency frequency}
 {:fx/type frequency-controls
  :frequency frequency}]
</code></pre>
<p>At this point, we are starting to have a nice looking interface, but it doesn't
do anything. If you slide the slider, nothing happens. If your experience is
mostly with object-oriented GUI libraries, the way Cljfx does things will be a
little unfamiliar. If you've used the JavaScript library React, it employs a
similar model. Global state is stored in an atom. When you update that atom,
all the relevant controls are updated accordingly.</p>
<pre><code class="lang-clojure">; Cljfx global state
(def *state
  (atom {:frequency 440}))
</code></pre>
<p>Add middleware to the <code>renderer</code> that maps incoming data from the global state
atom to the component description to be rendered:</p>
<pre><code class="lang-clojure">(def renderer
  (fx/create-renderer
    :middleware (fx/wrap-map-desc assoc :fx/type root)))
</code></pre>
<p>Then modify <code>-main</code> to use <code>fx/mount-renderer</code> instead of calling <code>renderer</code>
directly. This will watch the global state atom for changes and rerender the
GUI accordingly.</p>
<pre><code class="lang-clojure">(defn -main [&amp; args]
  (Platform/setImplicitExit true)
  (fx/mount-renderer *state renderer))
</code></pre>
<p>In most of the other examples, I would now write a function for each control
that updates the other controls when its value changes. For example, the slider
must update the text field, and the text field must update the slider. Imagine
in the future I decide to add a meter to the UI that also needs to be updated
whenever the frequency changes. I would have to remember to add code to update
the meter to both the slider and the text field. With Cljfx, the slider just
has to update the value in the global state atom. Then the text field and any
controls we add in the future that depend on the frequency will automatically
update. Here's a function that will update the global state atom:</p>
<pre><code class="lang-clojure">; Update frequency in global state if it's a valid frequency
(defn set-frequency [freq]
  (when (and (&gt;= freq min-frequency) (&lt;= freq max-frequency))
    (swap! *state assoc :frequency freq)))
</code></pre>
<p>Then we can add an <code>:on-value-changed</code> property to the <code>:slider</code> that calls
this function:</p>
<pre><code class="lang-clojure">:on-value-changed #(set-frequency (position-&gt;frequency %))
</code></pre>
<p>and add an <code>:on-text-changed</code> property to the <code>:text-field</code>:</p>
<pre><code class="lang-clojure">:on-text-changed #(set-frequency (read-string %))
</code></pre>
<p>And that's it. When one changes, the other does too. Once you get your head
around it, it's a really elegant way to handle UI state.</p>
<p>It might be helpful to have a couple buttons to increase or decrease the
frequency by an octave. An <a target="_blank" href="https://en.wikipedia.org/wiki/Octave">octave</a> is
"the interval between one musical pitch and another with double its frequency."</p>
<pre><code class="lang-clojure">(defn octave-button [{:keys [frequency label modifier]}]
  {:fx/type :button
   :text label
   :on-action (fn [_] (set-frequency (* frequency modifier)))})
</code></pre>
<p>Now just add these buttons to the <code>:children</code> vector of the <code>:h-box</code> in the
<code>frequency-controls</code> map:</p>
<pre><code class="lang-clojure">[{:fx/type octave-button
  :frequency frequency
  :label "&lt;"
  :modifier 0.5}
 {:fx/type :h-box
  :alignment :center
  :spacing 5
  :padding {:top 0 :bottom 0 :left 20 :right 20}
  :children [{:fx/type :text-field
              :text (str frequency)
              :on-text-changed #(set-frequency (read-string %))}
             {:fx/type :label
              :text "Hz"}]}
 {:fx/type octave-button
  :frequency frequency
  :label "&gt;"
  :modifier 2}]
</code></pre>
<p>If you slide the slider, the text field updates accordingly. If you type a
number in the text field, the slider updates accordingly. All good, right? What
if a user (and you know they will) enters a number higher than 20,000 or a
letter?</p>
<p>JavaFX has a <code>TextFormatter</code> class for this purpose. The <code>TextFormatter</code> uses a
filter that can intercept and modify user input and a value converter that
converts the value of the text field to a specified type whenever the field
loses focus or the user hits Enter. The filter should be a function that
accepts a Java <code>TextFormatter.Change</code> object and either returns that object or
returns null (<code>nil</code> in Clojurese) to reject the change.</p>
<pre><code class="lang-clojure">; Text field limited to entering numbers within range that updates specified
; key in global state atom (state-key)
(defn num-filter [change]
  (let [input (.getControlNewText change)
        numified (read-string input)]
    (if (or (= input "") (number? numified))
        change
        nil)))
(defn number-field [{:keys [min-value max-value init-value state-key label]}]
  {:fx/type :h-box
   :alignment :center
   :spacing 5
   :padding {:top 0 :bottom 0 :left 20 :right 20}
   :children [{:fx/type :text-field
               :pref-column-count (+ 1 (count (str max-value)))
               :text-formatter {:fx/type :text-formatter
                                :value-converter :number
                                :filter num-filter
                                :value init-value
                                :on-value-changed #(cond (&lt; % min-value) (swap! *state assoc state-key min-value)
                                                         (&gt; % max-value) (swap! *state assoc state-key max-value)
                                                         :else (swap! *state assoc state-key %))}}
              {:fx/type :label
               :text label}]})
</code></pre>
<p>Cljfx doesn't provide wrappers for the methods of <code>TextFormatter.Change</code>, but
we can call the <code>getControlNewText()</code> method using Clojure's Java interop. This
method returns the complete new text wich will be used on the control after the
change. We can check this value to determine if we want to accept the change or
not.</p>
<p>A caveat here is that the value of <code>:filter</code> <a target="_blank" href="https://github.com/cljfx/cljfx/issues/114#issuecomment-754642403">must
be</a> a
top-level️ function. I wish I could define <code>:filter</code> as an anonymous function.
This would allow me to do something like also preventing the user from even
entering a number higher than the allowed range rather than just reverting to
the maximum value once the value is committed.</p>
<pre><code class="lang-clojure">:filter #(let [input (.getControlNewText %])
               numified (read-string input)]
           (if (or (= input "") (and (number? numified) (&lt;= max-value)))
               %
               nil))
</code></pre>
<p>If you try the above, it will throw a <code>Replace forbidden</code> error. That's because
<code>:filter</code> is a constructor argument of <code>TextFormatter</code> that cannot be modified
afterward. If you use an anonymous function, every call to <code>number-field</code>
(whenever the UI is being rerendered due to a change of state) will try to
create a new instance of the filter function, which is forbidden. But by making
<code>num-filter</code> a top-level function, it is now out of the scope of <code>max-value</code>. I
tried passing <code>max-value</code> to it by wrapping <code>num-filter</code> with a function that
takes <code>max-value</code> and calling that function in <code>:filter</code>, but that still
resulted in <code>Replace forbidden</code>. I also tried defining <code>max-value</code> at the
top-level and wrapping the map inside <code>number-field</code> with <code>binding</code> to reassign
the value of <code>max-value</code>, but since <code>num-filter</code> is being passed to the
<code>TextFormatter</code> and called later it is called outside the scope of the
<code>binding</code> and still unable to see <code>max-value</code>. I finally gave up and fell back
on just having the field revert to <code>max-value</code> once the value is committed. If
anyone has a solution for getting <code>max-value</code> to the <code>num-filter</code> function, I
welcome pull requests.</p>
<p>Now let's replace the baseline <code>:text-field</code> and the <code>:h-box</code> surrounding it
with our new <code>number-field</code>:</p>
<pre><code class="lang-clojure">{:fx/type number-field
 :min-value min-frequency
 :max-value max-frequency
 :init-value frequency
 :state-key :frequency
 :label "Hz"}
</code></pre>
<p>Let's use this <code>number-field</code> again to create a field to specify the duration
of the beep in milliseconds. First, let's add a key to our global state atom to
track duration:</p>
<pre><code class="lang-clojure">(def *state
  (atom {:frequency 440
         :duration 200}))
</code></pre>
<p>Then create our duration field:</p>
<pre><code class="lang-clojure">(defn general-controls [{:keys [frequency duration]}]
  {:fx/type :h-box
   :spacing 20
   :children [{:fx/type number-field
               :min-value 1
               :max-value 600000 ; 10 minutes
               :init-value duration
               :state-key :duration
               :label "ms"}]})
</code></pre>
<p>Add this to the <code>:children</code> vector of the <code>:v-box</code> in the <code>root</code> map:</p>
<pre><code class="lang-clojure">[{:fx/type frequency-slider
  :frequency frequency}
 {:fx/type frequency-controls
  :frequency frequency}
 {:fx/type general-controls
  :frequency frequency
  :duration duration}]
</code></pre>
<p>Frequency is rather abstract. Let's also give the user the ability to select a
musical note. We can store the corresponding frequencies for A4-G4 in a map.</p>
<pre><code class="lang-clojure">; Notes -&gt; frequency (middle A-G [A4-G4])
; http://pages.mtu.edu/~suits/notefreqs.html
(def notes {"A" 440.00
            "B" 493.88
            "C"261.63
            "D" 293.66
            "E" 329.63
            "F" 349.23
            "G" 292.00})
</code></pre>
<p>We'll give the user a drop-down menu. Whenever a note is selected from the
drop-down menu, we'll look up the frequency in the map and set that frequency
in the global state atom. We'll add it on to <code>general-controls</code>:</p>
<pre><code class="lang-clojure">(defn general-controls [{:keys [frequency duration]}]
  {:fx/type :h-box
   :spacing 20
   :children [{:fx/type number-field
               :min-value 1
               :max-value 600000 ; 10 minutes
               :init-value duration
               :state-key :duration
               :label "ms"}
              {:fx/type :h-box
               :alignment :center
               :spacing 5
               :children [{:fx/type :label
                           :text "♪"}
                          {:fx/type :choice-box
                           :items ["A" "B" "C" "D" "E" "F" "G"]
                           :on-value-changed #(set-frequency (notes %))}]}]})
</code></pre>
<p>Finally, let's make some noise.</p>
<pre><code class="lang-clojure">; Generate a tone using JSyn
; Adapted from https://github.com/daveyarwood/javasynth/blob/master/src/javasynth/getting_started.clj
(defn generate-tone [frequency duration amplitude]
  (let [synth (doto (. JSyn createSynthesizer) .start)
        out (LineOut.)
        sine (SineOscillator. frequency)]
    (.set (. sine -amplitude) amplitude)
    (.add synth out)
    (.add synth sine)
    (.connect (. sine -output) (. out -input))
    (let [now (. synth getCurrentTime)]
      (.start out)
      (. synth (sleepUntil (+ now (/ duration 1000))))
      (.stop synth))))
</code></pre>
<p>We'll use the Java <a target="_blank" href="http://softsynth.com/jsyn/index.php">JSyn library</a> we
imported at the very beginning to generate the tone. Leiningen will pull in
this dependency alongside Cljfx. Java has a standard <a target="_blank" href="https://openjdk.java.net/groups/sound/">Sound
API</a> that could be used to generate a
sine tone without any external dependencies, but it's a little too low-level
for what I'm trying to accomplish with this tutorial. This is a tutorial about
building a GUI with Clojure and not about sound processing with Clojure. If
you're interested, I did find a <a target="_blank" href="https://brainshave.com/blog/sound-synthesis/">well-written
tutorial</a> about using Clojure's
Java interop to generate a sine tone with Clojure via the Java Sound API. Wire
this function up to a button between the duration and note selector, and you're
ready to make some noise.</p>
<pre><code class="lang-clojure">(defn general-controls [{:keys [frequency duration]}]
  {:fx/type :h-box
   :spacing 20
   :children [{:fx/type number-field
               :min-value 1
               :max-value 600000 ; 10 minutes
               :init-value duration
               :state-key :duration
               :label "ms"}
              {:fx/type :button
               :text "Play"
               :on-action (fn [_] (generate-tone frequency duration 0.5))}
              {:fx/type :h-box
               :alignment :center
               :spacing 5
               :children [{:fx/type :label
                           :text "♪"}
                          {:fx/type :choice-box
                           :items ["A" "B" "C" "D" "E" "F" "G"]
                           :on-value-changed #(set-frequency (notes %))}]}]})
</code></pre>
<p><em>You can check out the entire example on <a target="_blank" href="https://github.com/goober99/lisp-gui-examples">GitHub</a>. This started as a personal learning project to explore the state of GUI programming in Lisp and has become a series of tutorials on building GUIs with various dialects of Lisp.</em></p>
]]></content:encoded></item><item><title><![CDATA[SELinux Has a UI Problem]]></title><description><![CDATA[If you ever troubleshoot a problem on Red Hat (or closely related distros such as Fedora and CentOS), you'll come across dozens of tutorials and articles that tell you to resolve the problem by disabling SELinux. It's not just random blog posts and q...]]></description><link>https://blog.matthewdmiller.net/selinux-has-a-ui-problem</link><guid isPermaLink="true">https://blog.matthewdmiller.net/selinux-has-a-ui-problem</guid><category><![CDATA[UI]]></category><category><![CDATA[UX]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Tue, 09 Apr 2019 17:31:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1610321253956/dym_FpGhi.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you ever troubleshoot a problem on Red Hat (or closely related distros such as Fedora and CentOS), you'll come across dozens of tutorials and articles that tell you to resolve the problem by disabling SELinux. It's not just random blog posts and questionable StackOverflow answers: I've seen this advice in the documentation and knowledge base articles for enterprise software.</p>
<p>Don't <a target="_blank" href="https://stopdisablingselinux.com/">disable SELinux</a>. Really, don't <a target="_blank" href="https://blog.centos.org/2017/07/dont-turn-off-selinux/">turn off SELinux</a>.</p>
<p>A <a target="_blank" href="https://blog.centos.org/2017/07/dont-turn-off-selinux/">post</a> on the official CentOS blog asks "[W]hy do articles feel the need to outright deactivate SELinux rather than help readers work through any problems they might have? Is SELinux that hard? Actually, it's really not." It doesn't have anything to do with SELinux being too difficult. SELinux has a UI problem.</p>
<p>When you say user interface (UI) design or user experience (UX), most people immediately think about graphical user interfaces (GUIs). A good UI is just as important for a command line application. If a command requires a lot of cumbersome flags or difficult-to-remember options, a user may use another app or *gasp* a GUI to accomplish the task. A software library also has a UI. The API is the UI with which a developer interacts with the library.</p>
<p>While SELinux is usually invisible to the user, it does have a UI. I'm not talking about the various tools including some GUIs that allow administrators to set policy. I'm talking about how SELinux gives the user feedback when they attempt to do something that is blocked by SELinux on why it was blocked or even that it was SELinux that blocked it.</p>
<p>Like any good sysadmin, I periodically run <code>yum update</code> to make sure I'm protected from any newly discovered vulnerabilities, but it is not without some trepidation that I do this. It's not often, but sometimes it breaks something that was working perfectly fine before.</p>
<p>The other day I did <code>yum update</code> on a server running Tomcat (fortunately, I did it on the test server first). Tomcat was working fine, but the web app deployed to Tomcat had stopped working. I tried redeploying the app and restarting Tomcat. Still nothing, so I then checked the Tomcat logs:</p>
<pre><code><span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.apache</span><span class="hljs-selector-class">.commons</span><span class="hljs-selector-class">.dbcp</span><span class="hljs-selector-class">.SQLNestedException</span>: <span class="hljs-selector-tag">Cannot</span> <span class="hljs-selector-tag">create</span> <span class="hljs-selector-tag">PoolableConnectionFactory</span> (<span class="hljs-selector-tag">IO</span> <span class="hljs-selector-tag">Error</span>: <span class="hljs-selector-tag">The</span> <span class="hljs-selector-tag">Network</span> <span class="hljs-selector-tag">Adapter</span> <span class="hljs-selector-tag">could</span> <span class="hljs-selector-tag">not</span> <span class="hljs-selector-tag">establish</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">connection</span>)
<span class="hljs-selector-tag">Caused</span> <span class="hljs-selector-tag">by</span>: <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.sql</span><span class="hljs-selector-class">.SQLRecoverableException</span>: <span class="hljs-selector-tag">IO</span> <span class="hljs-selector-tag">Error</span>: <span class="hljs-selector-tag">The</span> <span class="hljs-selector-tag">Network</span> <span class="hljs-selector-tag">Adapter</span> <span class="hljs-selector-tag">could</span> <span class="hljs-selector-tag">not</span> <span class="hljs-selector-tag">establish</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">connection</span>
<span class="hljs-selector-tag">Caused</span> <span class="hljs-selector-tag">by</span>: <span class="hljs-selector-tag">oracle</span><span class="hljs-selector-class">.net</span><span class="hljs-selector-class">.ns</span><span class="hljs-selector-class">.NetException</span>: <span class="hljs-selector-tag">The</span> <span class="hljs-selector-tag">Network</span> <span class="hljs-selector-tag">Adapter</span> <span class="hljs-selector-tag">could</span> <span class="hljs-selector-tag">not</span> <span class="hljs-selector-tag">establish</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">connection</span>
<span class="hljs-selector-tag">Caused</span> <span class="hljs-selector-tag">by</span>: <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.net</span><span class="hljs-selector-class">.ConnectException</span>: <span class="hljs-selector-tag">Permission</span> <span class="hljs-selector-tag">denied</span> (<span class="hljs-selector-tag">connect</span> <span class="hljs-selector-tag">failed</span>)
</code></pre><p>There is absolutely nothing here that indicates SELinux is even the problem. Yes, the end of the stack trace is <code>Permission denied</code>, but that sounds like it could mean the database account the web app is using is locked. I verified I was able to access the database over the network (I ran a simple query using SQL Developer from my workstation), I verified the server Tomcat was on in particular could access the database over the network (I ran a simple query using SQL*Plus), and I made sure the database account used by the web app was not locked.</p>
<p>I then turned to the web app vendor's support site. They had a knowledge base article on the error. It turns out a <code>tomcat_can_network_connect_db</code> SELinux boolean was added in RHEL 7.6. There is nothing special about a RHEL point release. They're basically just new installation media. All you need to do is install RHEL 7.x, and a <code>yum update</code> will get you to the latest point release. Setting aside that one shouldn't expect any breaking changes in a point release, it should have been made abundantly clear to the user when Tomcat couldn't connect to a database that the reason was this new SELinux boolean. This is a UI issue.</p>
<p>Most servers don't have a desktop environment installed. The primary way a user (here I'm talking about a user of the server such as an administrator not a user of the web app) interacts with the server is via SSH. In the case of servers, logs often are the UI.</p>
<p>Tomcat is where the problem was, so where am I going to look for the issue? In the Tomcat log, of course. A user-friendly UI then would put some kind of indication in the Tomcat log right alongside the database error that the database connection had been blocked by SELinux. I'm sure SELinux logged the policy violation in its own log, but that is only helpful if I know that SELinux is the issue. That's poor UI design on the part of SELinux.</p>
<p>Some might argue the blame is with Tomcat. Tomcat should log a more helpful error that indicates the issue is SELinux. Tomcat may not have been aware that the issue was SELinux. Tomcat runs on a variety of platforms and Linux distros, many of which do not have SELinux. The Tomcat developers may be unaware of changes to SELinux that could effect Tomcat. SELinux, on the other hand, knew this change would potentially break many Tomcat setups (<code>tomcat</code> is in the name of the boolean). I wasn't using a third-party build of Tomcat either; I was using the Tomcat straight from the Oracle Linux (based on RHEL) repo and <code>journalctl -u tomcat</code> to view the logs. Since everything is logged centrally via systemd, it seems SELinux should be able to log messages there as well. Why else force all logging through systemd? (I am no hater of systemd and actually think creating system services with systemd is a breeze compared to SysV-style init, but I'm not a fan of the way systemd handles logging.)</p>
<p>Why do so many people and vendors just recommend turning off SELinux? Because the SELinux UI is not user-friendly. In fact, the knowledge base article I found on the vendor's support site said the way to resolve the problem was to edit <code>/etc/selinux/config</code> and set <code>SELINUX=disabled</code>. I didn't do that. Since the article already identified the boolean, I turned that specific boolean on with <code>setsebool -P tomcat_can_network_connect_db 1</code> (the <code>-P</code> flag causes the change to persist after reboots).</p>
<p>This isn't an isolated experience. One time I was trying to configure Apache to serve files in a home directory. There was nothing in the Apache logs to indicate SELinux was the issue. I spent hours messing with file permissions and <code>chmod</code>ing directories before discovering the SELinux boolean <code>httpd_enable_homedirs</code>.</p>
<p>I feel the benefits of SELinux outweigh the inconvenience of the poor UI. I spent time troubleshooting the database when the problem had nothing to do with the database. I often use open source projects with a poor UI, because I feel the benefits of open source outweigh the bad design (though there are instances where I think the open source solution actually has a superior UI than its proprietary alternatives). But it would be nice if SELinux had a better UI, and if we want to win new users to open source, we need to improve our UI. SELinux needs to get better about indicating when something is blocked by SELinux in the location where the user is going to be looking for the problem (e.g. in the Tomcat log for Tomcat issues or the Apache log for Apache issues).</p>
]]></content:encoded></item><item><title><![CDATA[Vala Deserves a Closer Look]]></title><description><![CDATA[This is not really a post about Vala--though I do think Vala deserves a closer look. It is about the general philosophy of evaluating programming languages. I also wrote a post that's not really about Perl.
There are so many programming languages out...]]></description><link>https://blog.matthewdmiller.net/vala-deserves-a-closer-look</link><guid isPermaLink="true">https://blog.matthewdmiller.net/vala-deserves-a-closer-look</guid><category><![CDATA[programming languages]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Mon, 01 Apr 2019 22:23:49 GMT</pubDate><content:encoded><![CDATA[<p><em>This is not really a post about Vala--though I do think Vala deserves a closer look. It is about the general philosophy of evaluating programming languages. I also wrote <a target="_blank" href="https://dev.to/goober99/right-tool-for-the-job-but-chances-are-the-right-tool-is-perl-ck8#so-many-tools-to-choose-from">a post that's not really about Perl</a>.</em></p>
<p>There are so many programming languages out there that it's difficult to determine which are worth my attention. I've recently <a target="_blank" href="https://dev.to/goober99/right-tool-for-the-job-but-chances-are-the-right-tool-is-perl-ck8#so-many-tools-to-choose-from">started looking</a> for a new language to learn in an effort to continue expanding my tool set. I have an ever growing list of programming languages I would like to learn someday. One language that was not on that list was Vala.</p>
<p>I had dismissed Vala as a GNOME thing with little interest to those outside the GNOME community, but recently I had seen Vala pop up in a few unexpected places, so I decided to give it a closer look.</p>
<p>One of the ways I evaluate a programming language is to see what cool projects are being built with it. The way I do this is by going to GitHub's <a target="_blank" href="https://github.com/trending">trending page</a> and selecting the language from the Languages drop-down on the right.</p>
<p>If all I find is the language interpreter/compiler, a web application framework, and a few assorted libraries, I'm not usually going to spend much time on that language. I'm interested in languages that people are using to build cool things. Every language (no matter how obscure) seems to have at least one web application framework these days. The trending page for Crystal this month shows no fewer than four web frameworks: Amber, Amethyst, Kemal, and Lucky. Forth has <a target="_blank" href="https://www.1-9-9-1.com/">1991</a>. Nim has <a target="_blank" href="https://github.com/dom96/jester">Jester</a>. Smalltalk has <a target="_blank" href="https://en.wikipedia.org/wiki/Seaside_(software">Seaside</a>).</p>
<p>Nor do I really care that much about module counts. Your language may have four different libraries to parse JSON and multiple ORMs, but what I want to know is what are people building with those libraries. If people are building cool projects with a language, I think a strong ecosystem and useful libraries will follow.</p>
<p>I realize GitHub might not host all the cool things being done in a language, but I feel it is representative. Maybe cool things are being done in a language but they are proprietary. If a language is fun to use, I think it will be used for both proprietary and open source projects, so I think open source projects sufficient to judge a language. There could also be cool projects on SourceForge, GitLab, etc. For now, GitHub has by far the largest collection of open source projects, so it serves to give a pretty good survey of what is available in a given language.</p>
<h2 id="the-part-about-vala">The Part about Vala</h2>
<p>I guess since I do have Vala in the title, I should share some of the cool projects being built with Vala that convinced me to give it a closer look.</p>
<ul>
<li><p><a target="_blank" href="https://github.com/akiraux/Akira">Akira</a>. This is a UI/UX design tool for creating UI mock-ups. It hasn't even had a stable release yet, and it already has 1,526 stars on GitHub and $560/month pledged on <a target="_blank" href="https://www.patreon.com/akiraux">Patreon</a>. It has a really cool <a target="_blank" href="https://github.com/akiraux/Akira#official-mascot">mascot</a> too. The lead developer also has a <a target="_blank" href="https://github.com/Alecaddd/sequeler">SQL client</a> and <a target="_blank" href="https://github.com/Alecaddd/taxi">FTP client</a> written in Vala.</p>
</li>
<li><p><a target="_blank" href="https://github.com/johanmattssonm/birdfont">Birdfont</a>. Font editor. Many Linux distro's have packages in their repos, and there is a package in OpenBSD. There are also binaries for Windows and Mac. This project is evidence that Vala is not limited to GNOME. I also found it funny that GitHub thinks 11.3% of the source is written in Brainfuck because of the .bf extension used for fonts in the Birdfont format.</p>
</li>
<li><p><a target="_blank" href="https://github.com/phw/peek">Peek</a>. GIF screen recorder. Packaged for a lot of distros. Could be useful for creating animated screenshots for READMEs.</p>
</li>
<li><p><a target="_blank" href="https://github.com/pdfpc/pdfpc">pdfpc</a>. Presenter console with multi-monitor support for PDF files. Vala must be easy to learn or there are a lot of developers who already know it, because some of these projects are able to draw a lot of contributors. This project has 43 contributors with the latest commit 19 days ago.</p>
</li>
<li><p><a target="_blank" href="https://github.com/teejee2008/timeshift">Timeshift</a>. System restore tool for Linux. This is another Vala project with a small but active community. It has 30 contributors and users submitting issues and pull requests.</p>
</li>
<li><p><a target="_blank" href="https://github.com/p-e-w/finalterm">Final Term</a>. This was a terminal emulator with advanced features. It's no longer maintained, but it was very popular (it has 3,999 stars on GitHub).</p>
</li>
<li><p>Most of the default apps in elementary OS are written in Vala. I haven't used it (I won't give up my MATE desktop), but elementary OS is a popular Linux distro (currently #4 on DistroWatch). It's app store, audio player, calculator, calendar, email client, file manager, image viewer, panel, screenshot tool, terminal emulator, text editor, video player, and even it's window manager are all written in Vala. I question the necessity of needing to write so many of their own apps when there are already so many great options available for many of these, but they do have a consistent design aesthetic and ecosystem. Many third party apps written for elementary OS (but working with other distros) are also written in Vala (such as this <a target="_blank" href="https://github.com/babluboy/bookworm">eBook reader</a> and <a target="_blank" href="https://github.com/lainsce/quilter">focused writing app</a>).</p>
</li>
<li><p>Deepin is a popular Linux distro in China with it's own desktop environment. Unlike elementary OS which uses GTK, it uses Qt, yet it still employs Vala for a couple things. It's <a target="_blank" href="https://github.com/linuxdeepin/deepin-terminal">terminal emulator</a> and it's <a target="_blank" href="https://github.com/linuxdeepin/deepin-wm">window manager</a> (which started out as a fork of the elementary OS window manager) are both written in Vala.</p>
</li>
<li><p>There are some official GNOME apps written in Vala, but surprisingly, since Vala is a GNOME project, not very many. The GNOME <a target="_blank" href="https://gitlab.gnome.org/GNOME/baobab/">disk usage analyzer</a>, <a target="_blank" href="https://gitlab.gnome.org/World/deja-dup">backup tool</a>, and <a target="_blank" href="https://gitlab.gnome.org/GNOME/shotwell">photo manager</a> are written in Vala.</p>
</li>
<li><p>There's even a <a target="_blank" href="https://github.com/valum-framework/valum">web application framework</a> written in Vala.</p>
</li>
</ul>
<p>Vala may not have developers who "rewrite all the things" like Rust or the backing of a tech giant like Go and Reason. I've been averaging a new programming language every seven years, so this is a big decision. I'm taking my time. I'm considering making Rust or D my next language, but now I'm also considering Vala.</p>
]]></content:encoded></item><item><title><![CDATA[Learn LambdaNative by Example: Desktop GUI]]></title><description><![CDATA[This tutorial was updated on January 10, 2021 to generate a tone using LambdaNative instead of merely wrapping a Linux-only command-line program called beep that controls the PC speaker. This should now make it possible to follow this tutorial on any...]]></description><link>https://blog.matthewdmiller.net/learn-lambdanative-by-example-desktop-gui</link><guid isPermaLink="true">https://blog.matthewdmiller.net/learn-lambdanative-by-example-desktop-gui</guid><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Wed, 27 Mar 2019 21:19:28 GMT</pubDate><content:encoded><![CDATA[<p><em>This tutorial was updated on January 10, 2021 to generate a tone using LambdaNative instead of merely wrapping a Linux-only command-line program called beep that controls the PC speaker. This should now make it possible to follow this tutorial on any OS supported by LambdaNative. This tutorial can also be found in the <a target="_blank" href="https://github.com/goober99/lisp-gui-examples/blob/master/examples/lambdanative/tutorial.md">GitHub repo</a> with the example code. Pull requests for improving the example and tutorial are welcome.</em></p>
<p>LambdaNative is a cross-platform framework for developing desktop and mobile
apps using Scheme (built atop Gambit). Resources on LambdaNative seem to be
extremely scarce. I couldn't find a single step-by-step tutorial for using
LambdaNative, so hopefully my small contribution will benefit others trying to
get started with LambdaNative.</p>
<p>LambdaNative already includes a calculator demo, and frankly, I find making a
millionth calculator example to be a little dull. Instead I'll be building a
GUI for generating a tone. We're only going to be building a desktop GUI, so we
aren't going to be tapping into the full power of LambdaNative. Where it seems
LambdaNative would really be useful is enabling you to write cross-platform
mobile apps with Scheme! Unfortunately, that is outside the scope of this
tutorial. Maybe in the future I'll revisit LambdaNative and use it to create a
mobile app.</p>
<p><img src="https://github.com/goober99/lisp-gui-examples/blob/master/screenshots/lambdanative.png?raw=true" alt="Screenshot" /></p>
<h2 id="installing-lambdanative">Installing LambdaNative</h2>
<p>The LambdaNative wiki gives a <a target="_blank" href="https://github.com/part-cw/lambdanative/wiki/Getting-Started#required-tools-and-libraries">list of
dependencies</a>
that need to be installed with your distro's package manager before installing
LambdaNative. They give an <code>apt</code> command you can copy and paste to your
terminal to install all the needed dependencies on Ubuntu.</p>
<ul>
<li><p>Download the most recent <a target="_blank" href="https://github.com/part-cw/lambdanative/releases">release</a>.</p>
</li>
<li><p>Unzip the release to a system-wide location such as <code>/opt</code> or <code>/usr/local</code>.</p>
</li>
</ul>
<pre><code class="lang-bash">sudo unzip lambdanative-*.zip -d /opt
</code></pre>
<ul>
<li>Rename unzipped directory.</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /opt
sudo mv lambdanative* lambdanative
</code></pre>
<ul>
<li>Create the files <code>SETUP</code> and <code>PROFILE</code>. If you were developing a mobile app,
you would need to configure these files for the respective SDKs. Since that is
outside the scope of this tutorial, that is left as an exercise for the reader.</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> lambdanative
sudo cp SETUP.template SETUP
sudo cp PROFILE.template PROFILE
</code></pre>
<ul>
<li>Edit <code>scripts/lambdanative</code> and populate the <code>LAMBDANATIVE</code> variable with
<code>/opt/lambdanative</code>.</li>
</ul>
<pre><code class="lang-bash">LAMBDANATIVE=/opt/lambdanative
</code></pre>
<ul>
<li>Place the LambdaNative initialization script in the system path.</li>
</ul>
<pre><code class="lang-bash">sudo ln -s /opt/lambdanative/scripts/lambdanative /usr/bin/lambdanative
</code></pre>
<ul>
<li>Create and initialize a LambdaNative build directory.</li>
</ul>
<pre><code class="lang-bash">mkdir ~/lambdanative
<span class="hljs-built_in">cd</span> ~/lambdanative
lambdanative init
</code></pre>
<h2 id="creating-a-new-gui-app">Creating a New GUI App</h2>
<p>Your freshly initiated build directory will look like this:</p>
<pre><code>apps/
modules/
configure
Makefile
</code></pre><p>Your app will go in its own subdirectory in <code>apps</code>. To create a new app:</p>
<pre><code class="lang-bash">lambdanative create &lt;appname&gt; &lt;apptype&gt;
</code></pre>
<p>The options for <code>&lt;apptype&gt;</code> are <code>console</code>, <code>gui</code>, and <code>eventloop</code>. I created a
new GUI app called bleep:</p>
<pre><code class="lang-bash">lambdanative create bleep gui
</code></pre>
<p>This will create a directory in <code>apps</code> called <code>bleep</code> with several files in it.</p>
<h2 id="compiling-the-app">Compiling the App</h2>
<p>LambdaNative utilizes the GNU Build System.</p>
<pre><code class="lang-bash">./configure bleep
make
make install
</code></pre>
<p>By default, the build will target the local host. The first time you do this
will take awhile, because it is downloading and compiling prerequisites. These
prerequisites are cached to speed up subsequent compiles. If you get any errors
during the initial build, you probably missed installing a dependency. Install
it with your distro's package manager and then try compiling again.</p>
<p>You can also configure in debug mode. You will want to clean the cache with
<code>make scrub</code> so everything is rebuilt. It will take awhile since everything is
being rebuilt.</p>
<pre><code class="lang-bash">./configure bleep debug
make scrub
make
make install
</code></pre>
<p>In my experience, debug mode didn't help much. Runtime errors are logged to
<code>~/Desktop/log/*.txt</code>.</p>
<pre><code><span class="hljs-selector-attr">[SYSTEM]</span> <span class="hljs-selector-tag">2019-03-16</span> <span class="hljs-selector-tag">00</span><span class="hljs-selector-pseudo">:59</span><span class="hljs-selector-pseudo">:21</span>: <span class="hljs-selector-tag">Application</span> <span class="hljs-selector-tag">bleep</span> <span class="hljs-selector-tag">built</span> <span class="hljs-selector-tag">2019-03-16</span> <span class="hljs-selector-tag">00</span><span class="hljs-selector-pseudo">:59</span><span class="hljs-selector-pseudo">:14</span>
<span class="hljs-selector-attr">[SYSTEM]</span> <span class="hljs-selector-tag">2019-03-16</span> <span class="hljs-selector-tag">00</span><span class="hljs-selector-pseudo">:59</span><span class="hljs-selector-pseudo">:21</span>: <span class="hljs-selector-tag">Git</span> <span class="hljs-selector-tag">hash</span>
<span class="hljs-selector-attr">[ERROR]</span> <span class="hljs-selector-tag">2019-03-16</span> <span class="hljs-selector-tag">00</span><span class="hljs-selector-pseudo">:59</span><span class="hljs-selector-pseudo">:22</span>: <span class="hljs-selector-tag">primordial</span>: (assoc <span class="hljs-number">49</span> <span class="hljs-number">#f</span>): (Argument <span class="hljs-number">2</span>) <span class="hljs-selector-tag">LIST</span> <span class="hljs-selector-tag">expected</span>
<span class="hljs-selector-attr">[ERROR]</span> <span class="hljs-selector-tag">2019-03-16</span> <span class="hljs-selector-tag">00</span><span class="hljs-selector-pseudo">:59</span><span class="hljs-selector-pseudo">:22</span>: <span class="hljs-selector-tag">HALT</span>
</code></pre><p>Not very helpful, is it? So I enabled debug mode.</p>
<pre><code>[SYSTEM] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: Application bleep built <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">34</span>
[SYSTEM] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: Git hash
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: primordial: (assoc <span class="hljs-number">49</span> #f): (Argument <span class="hljs-number">2</span>) LIST expected
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: trace: <span class="hljs-regexp">/opt/</span>lambdanative/modules/ln_glgui/primitives.scm line=<span class="hljs-number">230</span> col=<span class="hljs-number">21</span>
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: trace: <span class="hljs-regexp">/opt/</span>lambdanative/modules/ln_glgui/primitives.scm line=<span class="hljs-number">273</span> col=<span class="hljs-number">21</span>
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: trace: <span class="hljs-regexp">/opt/</span>lambdanative/modules/ln_glgui/slider.scm line=<span class="hljs-number">80</span> col=<span class="hljs-number">8</span>
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: trace: <span class="hljs-regexp">/opt/</span>lambdanative/modules/ln_glgui/glgui.scm line=<span class="hljs-number">151</span> col=<span class="hljs-number">36</span>
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: trace: <span class="hljs-regexp">/opt/</span>lambdanative/modules/ln_glgui/glgui.scm line=<span class="hljs-number">145</span> col=<span class="hljs-number">11</span>
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: trace: <span class="hljs-regexp">/opt/</span>lambdanative/modules/ln_glgui/glgui.scm line=<span class="hljs-number">183</span> col=<span class="hljs-number">3</span>
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: trace: <span class="hljs-regexp">/opt/</span>lambdanative/modules/eventloop/eventloop.scm line=<span class="hljs-number">151</span> col=<span class="hljs-number">9</span>
[ERROR] <span class="hljs-number">2019</span><span class="hljs-number">-03</span><span class="hljs-number">-16</span> <span class="hljs-number">01</span>:<span class="hljs-number">16</span>:<span class="hljs-number">44</span>: HALT
</code></pre><p>It's definitely longer but still not very helpful. It actually includes line
numbers, which appears promising, but they are all line numbers in LambdaNative
modules. It doesn't actually trace the error all the way to the line in my app
causing the error. I spent a lot more time reading the source of the
LambdaNative modules than I would have liked.</p>
<p>And that's when the log file even contained an error. Sometimes the app failed
with a segmentation fault and there was no error in the log at all. I often
peppered my source with <code>(log-status "reached here")</code> and <code>tail -f</code> the log
file to debug and isolate errors.</p>
<p>Errors caught at compile time, on the other hand, were much nicer. If an error
occurred while compiling, the error message included the line number from my
app.</p>
<p>The development workflow is more akin to traditional compiled languages like C.
I missed the quick feedback I'm used to while developing Scheme on a REPL.
After the initial compile, subsequent compiles are much quicker.</p>
<pre><code class="lang-bash">$ time make

real  0m3.877s
user  0m2.652s
sys   0m0.605s
</code></pre>
<p>Four seconds can seem like a long time when you are making a series of small
changes or chasing down a bug. There is a
<a target="_blank" href="https://github.com/part-cw/lambdanative/wiki/Using-Emacs">module</a> for REPL
editing with Emacs. Since I don't use Emacs, I didn't give it a spin, but if I
was developing a larger app, I might give it a try.</p>
<p>The <code>install</code> step will move the executable to <code>~/Desktop/bleep/bleep</code> and
launch it. This will launch a rectangular window.</p>
<p><img src="https://github.com/goober99/lisp-gui-examples/blob/master/screenshots/lambdanative-rectangle.png?raw=true" alt="Screenshot" /></p>
<p>This window looks awful lonely. Let's add some widgets!</p>
<h2 id="coding-the-app">Coding the App</h2>
<p>If your interface will use text (such as labels on buttons), you must include a
<code>FONTS</code> file in your application subdirectory. I just copied the <code>FONTS</code> file
from one of the demos included with LambdaNative.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> apps/bleep
cp /opt/lambdanative/apps/LineDrop/FONTS .
</code></pre>
<p>This is what the file looks like:</p>
<pre><code><span class="hljs-attribute">DejaVuSans</span>.ttf <span class="hljs-number">8</span> <span class="hljs-number">18</span>,<span class="hljs-number">25</span> ascii
</code></pre><p>For a description of the file format, see the documentation of the file on the
<a target="_blank" href="https://github.com/part-cw/lambdanative/wiki/FONTS">LambdaNative wiki</a>.</p>
<p>Your application subdirectory will already contain a <code>main.scm</code>. This file
contains the basic skeleton for a GUI app (the black rectangle above):</p>
<pre><code class="lang-scheme">;; LambdaNative gui template

(define gui #f)

(main
;; initialization
  (lambda (w h)
    (make-window 320 480)
    (glgui-orientation-set! GUI_PORTRAIT)
    (set! gui (make-glgui))

    ;; initialize gui here

  )
;; events
  (lambda (t x y)
    (if (= t EVENT_KEYPRESS) (begin
      (if (= x EVENT_KEYESCAPE) (terminate))))
    (glgui-event gui t x y))
;; termination
  (lambda () #t)
;; suspend
  (lambda () (glgui-suspend) (terminate))
;; resume
  (lambda () (glgui-resume))
)

;; eof
</code></pre>
<p>I started by changing the comment at the top to</p>
<pre><code class="lang-scheme">;; bleep - GUI for generating a tone made with LambdaNative
</code></pre>
<p>The bulk of the skeleton consists of the <a target="_blank" href="https://github.com/part-cw/lambdanative/wiki/Index-of-Module-eventloop">event
loop</a>.
The <code>(main p1 p2 p3 p4 p5)</code> loop takes five functions as arguments:</p>
<table>
<thead>
<tr>
<td>Parameter</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>p1</td><td>Function to be run before the main loop is initialized. This is where you setup the GUI.</td></tr>
<tr>
<td>p2</td><td>Main loop function, which is called constantly throughout the application's life. This is where you listen for events like key presses. Since most widgets take a callback, you shouldn't need to do much in this area.</td></tr>
<tr>
<td>p3</td><td>Function to be run when the application is to be terminated.</td></tr>
<tr>
<td>p4</td><td>Function, which is called when the application is suspended.</td></tr>
<tr>
<td>p5</td><td>Function, which is called when the application is resumed.</td></tr>
</tbody>
</table>
<p>The functions supplied in the skeleton for p3, p4, and p5 should be sufficient
for most applications. We won't need to touch them.</p>
<pre><code class="lang-scheme">(make-window 540 360)
(glgui-orientation-set! GUI_LANDSCAPE)
</code></pre>
<p>I started by changing the dimensions and orientation of the window. Now let's
add some widgets to that initialization <code>lambda</code>. I copy and pasted the example
from the bottom of the <a target="_blank" href="https://github.com/part-cw/lambdanative/wiki/glgui-slider">slider documentation
page</a>.</p>
<pre><code class="lang-scheme">(set! sl (glgui-slider gui 20 20 280 60 1 5 #f White White Orange Black num_25.fnt num_20.fnt #f White))
(glgui-widget-set! gui sl 'showvalue #t)
</code></pre>
<p>If you are familiar with Scheme, that <code>set!</code> probably made you pause. Too many
exclamation marks in my Scheme code always make me nervous. I immediately start
wondering if there is a better way to write the code. As it should. Side
effects should be avoided when possible. I tried changing the <code>set!</code> to
<code>define</code> and got the following error when recompiling:</p>
<pre><code>*** ERROR IN <span class="hljs-string">"/home/matthew/lambdanative/apps/bleep/main.scm"</span>@97.<span class="hljs-number">5</span> -- Ill-placed <span class="hljs-string">'define'</span>
</code></pre><p>Gambit (the underlying Scheme implementation used by LambdaNative) only allows
<code>define</code>s at the beginning of a <code>lambda</code> body. This actually conforms with the
R[5-7]RS specs, but I'm used to Scheme implementations (such as Racket,
Chicken, and MIT/GNU Scheme) that allow <code>define</code> anywhere in a <code>lambda</code> body.
All the LambdaNative examples and demos use <code>set!</code>, so I used it as well.</p>
<p>We must specify the color for several elements of the slider. LambdaNative
doesn't use native widgets but draws its own widgets with OpenGL. I googled
"color schemes" for inspiration and specified a few colors at the top of the
script above the <code>(main)</code> loop that I could reference throughout the program.</p>
<pre><code class="lang-scheme">;; UI color palette
(define *background-color* (color-rgb 26 26 29))
(define *foreground-color* (color-rgb 195 7 63))
(define *accent-color* (color-rgb 111 34 50))
(define *text-color* (color-rgb 255 255 255))
;; Scale used by slider
(define *min-position* 0)
(define *max-position* 2000)
;; Range of frequencies
(define *min-frequency* 20)
(define *max-frequency* 20000)
</code></pre>
<p>The variable name <code>*background-color*</code> is just a Lisp naming convention for
global parameters. LambdaNative provides <code>(color-rgb r g b)</code> for creating
colors. I also defined variables for the scale used by the slider and the range
of frequencies accepted by beep.</p>
<p>We also need to specify the position and size of the slider. Both are specified
in pixels. There aren't percentages or other scalable units you may be familiar
with from CSS. There are functions to get the width and height of the window,
so you could code the math to make a widget 80% the width of the window. Since
we're dealing with a simple example with hard-coded window dimensions, I just
hard-coded the position and size as well. Note that you specify the position
along the y-axis as pixels from the bottom of the window. This seemed counter
intuitive to me, and I continually caught myself trying to specify pixels from
the top of the window.</p>
<pre><code class="lang-scheme">;; Background color
(let ((w (glgui-width-get))
      (h (glgui-height-get)))
(glgui-box gui 0 0 w h *background-color*))

;; Frequency slider
(set! slider (glgui-slider gui 20 280 500 60 *min-position* *max-position* #f White *foreground-color* *accent-color* #f ascii_18.fnt ascii_18.fnt #f White))
(glgui-widget-set! gui slider 'showlabels #f)
</code></pre>
<p>I set a background color for the entire window. The only way I could find to do
this was to create a <code>glgui-box</code> the size of the entire window and set the
color of the box. I also renamed the variable from <code>sl</code> to <code>slider</code>.
LambdaNative has the tendency to use short, non-descriptive variable names
throughout its examples and documentation. I prefer to use more descriptive
variable names. Replace the fonts in the example slider code with the fonts we
specified in the <code>FONTS</code> file. I also disabled the slider labels.</p>
<p>The range of frequencies audible by humans is typically between 20 Hz and 20
KHz (we lose the ability to hear some of those higher frequencies as we age).
The <a target="_blank" href="https://en.wikipedia.org/wiki/A440_(pitch_standard">musical note A above middle
C</a>) is 440 Hz. Since A4
serves as a general tuning standard, it seems like a sensible default.</p>
<p>The scale of 20 to 20,000 is so large that 440 wouldn't appear to move the
slider at all. Ideally, 440 would fall about the middle of the slider. To
achieve this, let's use a logarithmic scale.</p>
<p>I found a <a target="_blank" href="https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249">Stack Overflow
answer</a>
on how to map a slider to a logarithmic scale. The code given in the answer is
JavaScript, but it was easy enough to port to Scheme.</p>
<pre><code class="lang-scheme">;; Logarithmic scale for frequency (so middle A [440] falls about in the middle)
;; Adapted from https://stackoverflow.com/questions/846221/logarithmic-slider

(define min-freq (log *min-frequency*))
(define max-freq (log *max-frequency*))
(define frequency-scale (/ (- max-freq min-freq) (- *max-position* *min-position*)))
;; Convert slider position to frequency
(define (position-&gt;frequency position)
  (inexact-&gt;exact (round (exp (+ min-freq (* frequency-scale (- position *min-position*)))))))
;; Convert frequency to slider position
(define (frequency-&gt;position freq) (/ (- (log freq) min-freq) (+ frequency-scale *min-position*)))
</code></pre>
<p>I created two functions: one that takes the position on the slider and returns
the frequency (<code>position-&gt;frequency</code>) and another that takes a frequency and
returns the position on the slider (<code>frequency-position</code>). Now let's set the
initial position of our slider with the <code>frequency-&gt;position</code> function.</p>
<pre><code class="lang-scheme">(glgui-widget-set! gui slider 'value (frequency-&gt;position 440))
</code></pre>
<p>Underneath the slider is a text field showing the current frequency, buttons to
increase/decrease the frequency by one octave, and a play button.</p>
<pre><code class="lang-scheme">;; Frequency display
(set! frequency-field (glgui-inputlabel gui 210 230 80 30 "440" ascii_18.fnt *text-color* *foreground-color*))
(glgui-widget-set! gui frequency-field 'align GUI_ALIGNCENTER)
(set! frequency-label (glgui-label gui 290 230 40 30 "Hz" ascii_18.fnt *foreground-color* *accent-color*))
(glgui-widget-set! gui frequency-label 'align GUI_ALIGNCENTER)

;; Octave buttons
(set! lower-button (glgui-button-string gui 140 230 50 30 "&lt;" ascii_18.fnt (lambda (g w t x y) #t)))
(set! higher-button (glgui-button-string gui 350 230 50 30 "&gt;" ascii_18.fnt (lambda (g w t x y) #t)))

;; Play button
(set! play-button (glgui-button-string gui 230 125 80 50 "Play" ascii_25.fnt (lambda (g w t x y) #t)))
</code></pre>
<p>That last argument to <code>glgui-button-string</code> is a callback function. This is a
function that is called when the button is pressed. I'm just trying to get the
widgets layed out right now. I don't yet care about the function of the button,
so I used anonymous functions (lambdas) that don't do anything for now.</p>
<p>The buttons do come with some default styling, but you'll probably want to
tweak the look to fit your color scheme and UI design. We can use
<code>glgui-widget-set!</code> to set parameters of a widget. Buttons have various
parameters that can be set such as <code>'button-normal-color</code> and
<code>'button-selected-color</code>.</p>
<pre><code class="lang-scheme">(glgui-widget-set! gui play-button 'button-normal-color *foreground-color*)
(glgui-widget-set! gui play-button 'button-selected-color *accent-color*)
(glgui-widget-set! gui play-button 'solid-color #t)
(glgui-widget-set! gui play-button 'rounded #f)
</code></pre>
<p>That seems like a lot to type (or copy and paste) for each button. With CSS I'm
able to define a style for all buttons or apply a class to buttons. I used a
<code>for-each</code> loop to loop through all the buttons and apply the above styling:</p>
<pre><code class="lang-scheme">;; Style buttons
(for-each (lambda (button)
            (glgui-widget-set! gui button 'button-normal-color *foreground-color*)
            (glgui-widget-set! gui button 'button-selected-color *accent-color*)
            (glgui-widget-set! gui button 'solid-color #t)
            (glgui-widget-set! gui button 'rounded #f))
          (list lower-button higher-button play-button))
</code></pre>
<p>At this point, we are starting to have a nice looking interface, but it doesn't
do anything. If you click the buttons or slide the slider, nothing happens.
While the buttons take a callback function parameter, I couldn't find a way to
wire up the slider to a function. I read the <a target="_blank" href="https://github.com/part-cw/lambdanative/wiki/glgui-slider"><code>glgui-slider</code> documentation
page</a> several times
searching for clues.</p>
<p>Finally, I resorted to looking at the source code for <code>glgui-slider</code>. Each of
the widget documentation pages link directly to their implementation in the
LambdaNative GitHub repo. I already mentioned that I ended up reading the
LambdaNative source more than I would have liked for debugging. Documentation
is one area where LambdaNative really could stand to improve. I scanned
<code>slider.scm</code> and discovered it had a <code>'callback</code> parameter. I created a
function that would set the frequency displayed in the <code>glgui-inputlabel</code> to
the one that corresponded to the position of the <code>glgui-slider</code>.</p>
<pre><code class="lang-scheme">;; Link slider to text field display of frequency
(define (adjust-frequency)
  (glgui-widget-set! gui frequency-field 'label (number-&gt;string
    (position-&gt;frequency (glgui-widget-get gui slider 'value)))))
</code></pre>
<p>and wired it up to the slider:</p>
<pre><code class="lang-scheme">(glgui-widget-set! gui slider 'callback (lambda (parent widget event x y) (adjust-frequency)))
</code></pre>
<p>A callback function takes five arguments. In the code examples in the
LambdaNative documentation, these always appeared as <code>(lambda (g w t x y))</code>.
These one-letter variables aren't very descriptive, and the arguments of the
callback functions don't appear to be documented. Through experimentation and
reading the source code and examples, I worked out the following:</p>
<table>
<thead>
<tr>
<td>Parameter</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>g</td><td>The [G]UI the widget belongs to. I used the name <code>parent</code> for this variable in my callback functions.</td></tr>
<tr>
<td>w</td><td>The [w]idget that triggered the callback function. I used the name <code>widget</code> for this variable in my callback functions.</td></tr>
<tr>
<td>t</td><td>The [t]ype of event. I used the name <code>event</code> for this variable in my callback functions.</td></tr>
<tr>
<td>x</td><td>First argument of event (x coordinate in pixels, keyboard character, etc.)</td></tr>
<tr>
<td>y</td><td>Second argument of event (y coordinate in pixels, modifier flags, etc.)</td></tr>
</tbody>
</table>
<p>The callback function is only called once the user releases the slider handle.
I want the user to get feedback as they drag the slider. You can write your own
event handling code in the <code>lambda</code> that forms the second parameter of
<code>(main)</code>. The generated skeleton already includes code to terminate the
application when the <code>Esc</code> key is pressed. I added some code to call
<code>adjust-frequency</code> when the slider handle is being dragged:</p>
<pre><code class="lang-scheme">;; events
  (lambda (t x y)
    (if (= t EVENT_KEYPRESS) (begin
      (if (= x EVENT_KEYESCAPE) (terminate))))
    ;; Also update frequency when dragging slider (callback is only on release)
    (if (and (glgui-widget-get gui slider 'downval) (= t EVENT_MOTION)) (adjust-frequency))
    (glgui-event gui t x y))
</code></pre>
<p>By looking at the implementation of <code>glgui-slider</code> in <code>slider.scm</code>, I noticed
that LambdaNative was setting a <code>'downval</code> parameter whenever the user was
holding down the mouse button on the slider handle. Whenever that parameter is
true, I listen for an <code>EVENT_MOTION</code> event to call <code>adjust-frequency</code>.</p>
<p>I replaced the anonymous lambdas in the octave button declarations with
callback functions called <code>decrease-octave</code> and <code>increase-octave</code>. An
<a target="_blank" href="https://en.wikipedia.org/wiki/Octave">octave</a> is "the interval between one
musical pitch and another with double its frequency."</p>
<pre><code class="lang-scheme">;; Set frequency slider and display
(define (set-frequency freq)
  (glgui-widget-set! gui slider 'value (frequency-&gt;position freq))
  (glgui-widget-set! gui frequency-field 'label (number-&gt;string freq)))
;; Buttons increase and decrease frequency by one octave
(define (adjust-octave modifier)
  (let ((new-freq (* (string-&gt;number (glgui-widget-get gui frequency-field 'label)) modifier)))
    (if (and (&gt;= new-freq *min-frequency*) (&lt;= new-freq *max-frequency*)) (set-frequency new-freq))))
(define (decrease-octave parent widget event x y) (adjust-octave 0.5))
(define (increase-octave parent widget event x y) (adjust-octave 2))
</code></pre>
<p>The <code>'aftercharcb</code> callback of <code>glgui-inputlabel</code> is called after each
character is typed or deleted. We can use this to update the slider as a user
enters a frequency. What if a user (and you know they will) enters a number
higher than 20,000 or a letter? We need a function that will only allow numbers
within a given range.</p>
<pre><code class="lang-scheme">;; Only allow numbers within range of min-value and max-value
(define (num-only min-value max-value old-value)
  (lambda (parent widget)
    (let* ((current-value (glgui-widget-get parent widget 'label))
           (current-numified (string-&gt;number current-value)))
      (if (or (= (string-length current-value) 0) ; Allow field to be empty
              (and current-numified (&gt;= current-numified min-value) (&lt;= current-numified max-value)))
          (set! old-value current-value)
          (glgui-widget-set! parent widget 'label old-value)))))
</code></pre>
<p>If the user types a character that makes the value invalid, we want to revert
to the last known good value. To accomplish this, I used a closure to remember
the last known value. Many programming languages today have closures, but
Scheme practically invented them. A closure enables variables to be associated
with a function that persist through all the calls of the function.</p>
<p>Now we can wire the <code>glgui-inputlabel</code> callback up to these functions.</p>
<pre><code class="lang-scheme">(set! frequency-range (num-only *min-frequency* *max-frequency* (glgui-widget-get gui frequency-field 'label)))
(glgui-widget-set! gui frequency-field 'aftercharcb (lambda (parent widget event x y)
  (frequency-range parent widget)
  (let ((freq (string-&gt;number (glgui-widget-get parent widget 'label))))
    (if freq (glgui-widget-set! parent slider 'value (frequency-&gt;position freq))))))
</code></pre>
<p>We call the <code>num-only</code> closure specifying the allowed range and initial value
which returns a new function that can be used in the callback. After we make
sure there are no high jinks going on with the value using the function created
by the closure (<code>frequency-range</code>), we update the position of the slider using
the current value of the text field.</p>
<p>We can use the  <code>num-only</code> closure again to create a field to specify the
duration of the beep in milliseconds:</p>
<pre><code class="lang-scheme">;; General Controls
(glgui-label gui 20 40 80 30 "Duration" ascii_18.fnt *foreground-color*)
(set! duration-field (glgui-inputlabel gui 110 40 80 30 "200" ascii_18.fnt *text-color* *foreground-color*))
(glgui-widget-set! gui duration-field 'align GUI_ALIGNCENTER)
(set! duration-range (num-only 1 600000 (glgui-widget-get gui duration-field 'label)))
(glgui-widget-set! gui duration-field 'aftercharcb (lambda (parent widget event x y) (duration-range parent widget)))
(glgui-label gui 195 40 40 30 "ms" ascii_18.fnt *foreground-color*)
</code></pre>
<p>Frequency is rather abstract. Let's also give the user the ability to select a
musical note. We can store the corresponding frequencies for A4-G4 in a table.</p>
<pre><code class="lang-scheme">;; Notes -&gt; frequency (middle A-G [A4-G4])
;; http://pages.mtu.edu/~suits/notefreqs.html
(define notes (list-&gt;table '((0 . 440.00)    ; A
                             (1 . 493.88)    ; B
                             (2 . 261.63)    ; C
                             (3 . 293.66)    ; D
                             (4 . 329.63)    ; E
                             (5 . 349.23)    ; F
                             (6 . 292.00)))) ; G
</code></pre>
<p>We'll give the user a drop-down menu. Whenever a note is selected from the
drop-down menu, we'll look up the frequency in the table and set it using the
<code>set-frequency</code> helper function we created for the octave buttons.</p>
<pre><code class="lang-scheme">(glgui-label gui 410 40 60 30 "Note" ascii_18.fnt *foreground-color*)
(set! note (glgui-dropdownbox gui 470 40 50 30
  (map (lambda (str)
    (lambda (lg lw x y w h s) (if s (glgui:draw-box x y w h *foreground-color*))
      (glgui:draw-text-left (+ x 5) y (- w 10) h str ascii_18.fnt *text-color*)))
    (list "A" "B" "C" "D" "E" "F" "G"))
  *accent-color* *foreground-color* *accent-color*))
(glgui-widget-set! gui note 'scrollcolor *accent-color*)
(glgui-widget-set! gui note 'callback (lambda (parent widget event x y)
  (set-frequency (table-ref notes (glgui-widget-get parent widget 'current)))))
</code></pre>
<p>Now, let's make some noise. LambdaNative has a rtaudio module. We'll use that
to generate a tone with a sine wave. Edit the <code>MODULES</code> file in your
applications subdirectory and add rtaudio to the list. The Scheme API of the
rtaudio module consists of essentially just two functions: <code>rtaudio-start</code> and
<code>rtaudio-stop</code>. You must first register four real-time hooks (an initialization
hook, input hook, output hook, and close hook) in a chunk of C code embedded
within your Scheme code. I wish the rtaudio module had an API that allowed
implementing these hooks in pure Scheme. Thankfully the
<a target="_blank" href="https://github.com/part-cw/lambdanative/tree/master/apps/DemoRTAudio">DemoRTAudio</a>
app included with LambdaNative implements a sine wave, and I was able to copy
and paste most of what I needed from there without spending a lot of time
trying to figure out how to write a sine wave in C myself.</p>
<pre><code class="lang-scheme">;; Register C-side real-time audio hooks
(c-declare  #&lt;&lt;end-of-c-declare

#include &lt;math.h&gt;

void rtaudio_register(void (*)(int), void (*)(float), void (*)(float*,float*), void (*)(void));

double f;
double srate=0;
float buffer;

void my_realtime_init(int samplerate) { srate=(double)samplerate; buffer=0; }
void my_realtime_input(float v) { }
void my_realtime_output(float *v1,float *v2) {
  static double t=0;
  buffer = 0.95*sin(2*M_PI*f*t);
  *v1=*v2=(float)buffer;
  t+=1/srate;
}
void my_realtime_close() { buffer=0; }

end-of-c-declare
)
(c-initialize "rtaudio_register(my_realtime_init,my_realtime_input,my_realtime_output,my_realtime_close);")
</code></pre>
<p>The <a target="_blank" href="http://pld.cs.luc.edu/telecom/mnotes/digitized_sound.html">basic formula for a sine
wave</a> is A sin(2πft)
where <em>A</em> is amplitude, <em>f</em> is frequency, and <em>t</em> is time. We need a way to
pass the frequency from our slider in the Scheme to the output hook in the C.
Gambit scheme has a <code>c-lambda</code> special form that makes it possible to create a
Scheme function that is a representative of a C function or code sequence.</p>
<pre><code class="lang-scheme">(define rtaudio-frequency (c-lambda (double) void "f=___arg1;"))
</code></pre>
<p>This creates a Scheme function that sets the f variable in our C chunk. Now
let's create a Schem function that will set the frequency and start and stop
the real-time audio subsystem.</p>
<pre><code class="lang-scheme">;; Generate a tone using the rtaudio module
(define (generate-tone parent widget event x y)
  ; Make sure neither frequency or duration were left blank
  (if (= (string-length (glgui-widget-get parent frequency-field 'label)) 0) (set-frequency 1))
  (if (= (string-length (glgui-widget-get parent duration-field 'label)) 0) (glgui-widget-set! parent duration-field 'label "1"))
  (rtaudio-frequency (exact-&gt;inexact (string-&gt;number (glgui-widget-get parent frequency-field 'label))))
  (rtaudio-start 44100 0.5)
  (thread-sleep! (/ (string-&gt;number (glgui-widget-get parent duration-field 'label)) 1000))
  (rtaudio-stop))
</code></pre>
<p>When playing a note such as B4 (493.88 Hz) that has a decimal point, the type
passed from Scheme to C lines up with the C type <code>float</code>, but when passing an
integer (such as 440), it will cause an error. The <code>exact-&gt;inexact</code> conversion
forces Scheme to pass the value along as a <code>float</code>. Wire this up to the play
button, and you're ready to make some noise.</p>
<pre><code class="lang-scheme">(set! play-button (glgui-button-string gui 230 125 80 50 "Play" ascii_25.fnt generate-tone))
</code></pre>
<p>LambdaNative has a lot of rough edges, not least of which is the documentation
(or lack thereof). Looking at the source code for a widget seems to be the only
way to determine all the parameters available for that widget. If you're like
me, being able to write mobile apps in Lisp is a dream come true! LambdaNative
may not be the smoothest development experience right now, but I hope to
revisit it again in the future. It is being actively developed (and has the
backing of a university research team), so my hopes are high for the future of
LambdaNative.</p>
<p><em>You can check out the entire example on <a target="_blank" href="https://github.com/goober99/lisp-gui-examples">GitHub</a>. This started as a personal learning project to explore the state of GUI programming in Lisp and has become a series of tutorials on building GUIs with various dialects of Lisp.</em></p>
]]></content:encoded></item><item><title><![CDATA[Right tool for the job, but chances are the right tool is Perl.]]></title><description><![CDATA[The title is intentionally provocative. This is not really a post about Perl--though I do think Perl usually is the right tool (at least for me). It is about the general philosophy of picking a language for a project and learning new languages.
Chanc...]]></description><link>https://blog.matthewdmiller.net/right-tool-for-the-job-but-chances-are-the-right-tool-is-perl</link><guid isPermaLink="true">https://blog.matthewdmiller.net/right-tool-for-the-job-but-chances-are-the-right-tool-is-perl</guid><category><![CDATA[perl]]></category><category><![CDATA[programming languages]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Fri, 22 Mar 2019 02:45:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1610321268461/-G_jxe3eX.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>The title is intentionally provocative. This is not really a post about Perl--though I do think Perl usually is the right tool (at least for me). It is about the general philosophy of picking a language for a project and learning new languages.</em></p>
<h2 id="chances-are-the-right-tool-is-insert-language-here">Chances are the right tool is [insert language here]</h2>
<p>I sometimes spend days before starting a new project agonizing over what language I should use. I often create elaborate text files comparing the features, libraries, and ecosystems of several different languages as they relate to the project. I want the right tool for the job.</p>
<p><a target="_blank" href="http://www.commitstrip.com/en/2017/03/16/when-we-leave-coders-to-do-their-own-thing/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610321265108/RKargs3mH.jpeg" alt="Comic" /></a></p>
<p>After all that, I usually end up going with Perl. Perl is my favorite programming language. It's what I'm most familiar with. In most cases, Perl is the right tool.</p>
<p>You may have a different language that you're most experienced with. In that case, chances are the right tool is [insert language here]. Insert your preferred programming language.</p>
<p>Like many hackers, I began with HTML and CSS. I started learning HTML and CSS when I was around 12 years old. I quickly progressed to JavaScript. I spent hours on the computers at school trying to build games and utilities that ran in the browser. I built an on-screen keyboard for...I don't really know why. I started working on a JavaScript Settlers of Catan that I never finished.</p>
<p>In high school, I got an after-school job and had actual money. I graduated from GeoCities to my own domain name and cheap web host. It wasn't long before I wanted to do more than just countdowns and animations in the browser. I wanted to learn the black magic of server-side programming. I remember choosing between learning Perl and PHP. I don't remember why I chose Perl. Maybe it was because I found a book about Perl on clearance at a mall bookstore. Maybe history would be different if I had picked up a PHP book instead. Had Node.js existed at that time, maybe I would have never been motivated to move beyond JavaScript.</p>
<p>Perl was the first programming language I fell in love with. I didn't dislike JavaScript, but I only ever used it as a means to an end. I wanted to create my own programs, and JavaScript and a browser allowed me to do that. With Perl it was different. I enjoyed Perl. It was fun to hack.</p>
<p>I wrote my own CMS for my website...from scratch. I'm wise enough now not to try that again, but it was a rite of passage (plus, before that, my website had been completely hand-coded HTML).</p>
<p>Perl provided me my first paying developer position as a student worker my freshman year in college (albeit, as a student worker, it was minimum wage and limited to ten hours per week). Students scanned their ID cards as they entered and left the weekly chapel service. A certain number of chapels were required each semester. At that time, the card scans were saved to a text file on a network drive. I wrote a Perl script that processed the files, stored the data in a SQL Server database, and created a web interface that allowed the dean to run reports on how many chapels students had attended and enabled students to view how many more chapels they needed to attend to meet the requirement for the semester. After coding the CMS for my personal website with nothing but <a target="_blank" href="https://metacpan.org/pod/distribution/CGI/lib/CGI.pod">CGI.pm</a>, I was wise enough to pick <a target="_blank" href="https://metacpan.org/pod/CGI::Application">CGI::Application</a> for this project. (Today I usually use <a target="_blank" href="https://mojolicious.org/">Mojolicious</a> whenever I need to create a web app or web interface.)</p>
<p>Today I work at that same university as a DBA. Recently a co-worker dug up a copy of that web app I wrote as a freshman (thankfully the university has since moved off that homegrown solution to an off-the-shelf solution). I was appalled at the code. Both Perl and I have changed a lot in fifteen years. Even as a DBA, Perl is still the tool in my tool chest I most often turn to. Most of the tasks I need to solve involve getting data out of (or into) a database, formatting it (usually as CSV or XML), and sometimes using an API or SFTP to integrate it with a third party. Those are the kind of tasks Perl excels at. CPAN has <a target="_blank" href="https://metacpan.org/pod/DBI">DBI</a>, <a target="_blank" href="https://metacpan.org/pod/Text::CSV">Text::CSV</a>, and <a target="_blank" href="https://metacpan.org/pod/distribution/perl-ldap/lib/Net/LDAP.pod">Net::LDAP</a>.</p>
<h2 id="except-when-it-isnt">...except when it isn't.</h2>
<p>Right tool for the job will usually mean using more than one language on a project. Even if you're writing the back-end of your web app in Perl (or Ruby or Python or Groovy), you're going to need HTML to build what your user will see in their browser, CSS to style it, and JavaScript if you want any client-side interaction. I think all of these are so obvious most developers don't even give it a second thought. When I talk about choosing a language for my next web app, I'm talking about whether I should go with Perl that I'm familiar with or try out something new like Erlang for the back-end. HTML, CSS, and JavaScript are a given.</p>
<p>If my app needs to query a relational database, I'm going to use SQL. I've tried a couple different ORMs, and maybe I'm biased because I'm a DBA, but I always find working with SQL directly to be a better experience. I think what a lot of developers are trying to avoid with ORMs is mixing SQL and Perl. I agree that's ugly. I keep my SQL in separate files and load it with <a target="_blank" href="https://metacpan.org/pod/Template::Toolkit">Template::Toolkit</a>. Treating my SQL as templates, I'm able to do a lot more than I could with just bind variables.</p>
<p>While SQL is the right tool for querying databases, most database vendors have extended SQL to turn it into a Turing complete, general-purpose programming language. In the case of Oracle (the database at work), that is PL/SQL. I know I'm a DBA, but I find PL/SQL particularly unpleasant. It is very verbose. What I could do in a few lines of Perl takes me tens of lines of PL/SQL. We have an emergency notification service we use to send texts to all students and employees in the case of an emergency. On a regular basis, we need to export mobile phone numbers from our database, format them in a particular format, and transfer them using WebDAV to the service. My predecessor had implemented this as a stored procedure written in PL/SQL. We had need to make some changes to the output format. I decided to rewrite it in Perl, and I haven't regretted my decision for a second.</p>
<p>I also know a co-worker who did the opposite. We recently hired a new analyst. The analyst he replaced had a lot of Perl scripts to automate formatting files and such. The new analyst is rewriting most of these in PowerShell. Even though I think Perl excels at automation and formatting files, PowerShell is probably the right tool for him, because he is more familiar with PowerShell. I tried to convince the co-worker of the benefits of learning Perl, but ultimately I wasn't successful.</p>
<p>I like to tinker with the Arduino. I can use other languages on the Arduino, but because of the ease of use of the Arduino IDE, chances are the right tool is the Arduino language.</p>
<p>I haven't done any mobile app development yet, but I would like to develop a mobile app someday (even if just for fun). In that case, the right tool is often dictated by what is supported by the mobile platform you're targeting. If I want to write an Android app, I could choose Kotlin. For an iOS app, Swift is probably the right tool. I could also choose a cross-platform framework such as LambdaNative, Flutter, or React Native.</p>
<p>Most of the time performance is not really that big of a factor in choosing the right tool. Developer productivity often outweighs shaving off a few milliseconds of processing time. For most applications, whatever language you're most familiar with is probably fast enough. There are exceptions though.</p>
<p>I know Electron is everyone's favorite punching bag right now, so I hate to heap on more criticism, but it's mostly deserved. I've tried using VS Code. It is attractive and has some cool features, but it's also slow as molasses. If I have a few tabs open (say a Perl script, HTML document, and CSS style sheet), it takes several seconds when switching between tabs. My workstation is a Core 2 Duo with 8 GB of RAM. I know, I know, Moore's law and all that, but I shouldn't be forced to upgrade my computer just to use a text editor. It's not like I'm trying to play a realistic 3D game. Maybe you have an app you wrote with Electron and it is simple enough that it performs well even on older systems. Good for you. Then Electron probably is the right tool for you. But I would say that Electron was the wrong tool for VS Code (not that me saying that really matters).</p>
<p>I'm working on a project where I'm writing a FUSE file system to mount a cloud service. My first thought was that something like a FUSE file system might be one job where my beloved Perl might not be the right tool. For performance reasons, I thought I would need to write it in a compiled language like C or Rust. Then I came across an article about writing a network file system in Python, and that any latency from the network outweighed choosing Python. Sure enough there was a <a target="_blank" href="https://metacpan.org/pod/Fuse">CPAN module</a> with FUSE bindings. I did some tests, and Perl was more than fast enough. I should have never doubted.</p>
<p>I also write scripts in Bash and AWK. For simple system administration tasks, they are the right tools.</p>
<h2 id="so-many-tools-to-choose-from">So Many Tools to Choose From</h2>
<p>I have an ever growing list of programming languages I would like to learn someday. Lately dependent types have caught my interest, and I would like to learn Agda (or maybe I should learn Idris instead). Rust seems to be the latest hotness, and I would like to learn a compiled language. I've wanted to learn Ruby almost since I first learned to program, but I've never got around to it.</p>
<p>I've read articles that recommend learning a new programming language every year. I like the idea, but I average more like a new programming language every seven years. There's a book titled <em>Seven Languages in Seven Weeks.</em> Madness, pure madness, I say. I'm somewhat ashamed to admit the list of languages I know is short (in the order I learned them): JavaScript, Perl, and Scheme.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610321267096/9hlYvosR4.jpeg" alt="Books" /></p>
<p>Well, I guess it kind of depends on what you mean by "know a language." I consider myself to have mastered JavaScript, Perl, and Scheme. I know the idioms. I'm familiar enough with the ecosystems to know what libraries and frameworks best fit a situation. I can write simple programs without consulting the documentation. I have created at least one non-trivial project with each.</p>
<p>After I had known Perl for several years, probably inspired by one of those many learn a new programming language blog posts, I decided to expand my horizons. I had heard all kinds of wonderful things about functional programming, so I wanted to learn a functional language. I considered Haskell, but I had a friend who had actually majored in computer science (I majored in religion and have never taken a computer science or programming class) that a class on Haskell had been one of his most difficult classes, so I sought out a more gentle introduction to the world of functional programming. I was drawn to Lisp and finally decided upon (for reasons I no longer remember) the Scheme dialect.</p>
<p>I'm also comfortable with HTML, CSS, SQL, Bash, AWK, YAML, JSON, and the list probably goes on. I take these as a given though. They are necessary tools that go along with being a developer. I guess if you're an embedded software engineer who only ever writes C for embedded systems, you may not know HTML and CSS. If you're a Windows developer, maybe you don't need Bash (but I assume you do know some equivalent like PowerShell).</p>
<p>Programming languages share a lot in common. If you know JavaScript, even if you've never used Python or C, you could probably understand a lot of source code written in either. In fact, I consider it an essential skill of a developer to be able to read source code in a language you don't know and at least be able to identify what certain sections of the code do.</p>
<p>If two programming languages use two different paradigms (say, object-oriented and functional), they may be more different than two languages of the same paradigm. That's why it's useful to learn at least one language from each paradigm, but even a C++ hacker shouldn't have too much trouble figuring out Haskell or OCaml source.</p>
<p>I've fixed bugs in or made minor modifications to programs written in C, COBOL (yes, parts of our ERP are still written in COBOL), Java, PHP, Python, and Ruby (and maybe a few more I've forgotten about). I don't consider any of these languages that I know. I was able to use my knowledge of programming in general to browse the source code, identify the relevant area of the code, look up any unfamiliar keywords or syntax in that area, and then make the needed change.</p>
<p>The university I work for recently changed the LMS we use. The analyst who supports the LMS could export grades to a CSV from the previous LMS that he could then import into our ERP. The new LMS doesn't have a feature to export grades manually. Instead you can configure an HTTPS endpoint that it publishes grades in CSV format to. The documentation gave an example PHP script that would take grades published to the endpoint and save them to a text file. We could, of course, have written our own endpoint in Perl, Ruby, Python, etc., but to save time we used the example from the documentation. I don't know PHP, but I was able to look up just enough info about the keywords in the example to make a few small modifications to it. (Now the analyst has requested a few more modifications, and I am seriously considering rewriting it in Perl to make it easier for me to maintain.)</p>
<p>We also recently switched from a proprietary COBOL compiler to GnuCOBOL to save money. Our ERP vendor only officially supports the proprietary compiler. We have an analyst who is old enough that he actually started out programming COBOL. His help (and reading the Wikipedia article on COBOL) was enough to make the few changes I needed to get the COBOL to compile with GnuCOBOL. I actually modified the Makefile (another language itself) to use sed to modify the COBOL right before compiling it. This way upgrades to our ERP won't overwrite our customizations to the COBOL.</p>
<p>I've also read the introductory tutorial on the websites of several languages I'm interested in and sometimes went on to solve a few Project Euler problems with the language. I don't consider those languages I know. I don't consider myself knowing the language until I've actually built something with it (and, no, a few Project Euler problems don't count).</p>
<p>I completed the <a target="_blank" href="https://tour.golang.org/">interactive tour</a> on the Go website. I didn't like the Go language (I felt like it was telling me what to do), but I think that tour should be the gold standard for language tutorials. Every language should have an interactive tutorial on their website like that one.</p>
<h2 id="the-joy-of-perl">The Joy of Perl</h2>
<p>I took the Go tour when I was thinking I would need to write the FUSE file system I mentioned above in a compiled language. It was disheartening. For me, programming is something I enjoy. Yes, I program for work, but I also program for fun on my own time. I enjoy programming in Perl. Go just didn't seem fun. If I used Go for the project, I feared I might not enjoy it.</p>
<p>I think that is one thing holding me back from learning more languages. What if I invest all this time into learning a new language, but then I don't enjoy the language?</p>
<p>I may also love the language and never find out if I don't give it a try. I learned Scheme after I had several years of Perl under my belt. I like Scheme a lot. I don't use it as much as I use Perl. The main reason is libraries. There is a CPAN module for almost anything I need. Even Racket with its batteries included philosophy and a package repository doesn't come close to what's available on CPAN.</p>
<p>I learned Scheme in 2011 (at least that's the date of my first commit of Scheme code on GitHub). If I don't want my average of a new language every seven years to slip, I better get to learning my next language. I want to create a ray tracer using <a target="_blank" href="https://github.com/petershirley/raytracinginoneweekend">Ray Tracing in One Weekend</a>. Maybe I'll write it in Rust. Or OCaml. Oh no, I feel days of research and detailed text files coming on. Maybe I'll end up doing it in Perl.</p>
<p><em>Cover photo by <a target="_blank" href="https://unsplash.com/photos/IClZBVw5W5A">Todd Quackenbush</a> on Unsplash. Title inspired by this [article] (https://dzone.com/articles/polyglot-programming-good).</em></p>
]]></content:encoded></item><item><title><![CDATA[Learn Racket by Example: GUI Programming]]></title><description><![CDATA[This tutorial was updated on January 10, 2021 to generate a tone using Racket instead of merely wrapping a Linux-only command-line program called beep that controls the PC speaker. This should now make it possible to follow this tutorial on any OS su...]]></description><link>https://blog.matthewdmiller.net/learn-racket-by-example-gui-programming</link><guid isPermaLink="true">https://blog.matthewdmiller.net/learn-racket-by-example-gui-programming</guid><category><![CDATA[GUI]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Matthew D. Miller]]></dc:creator><pubDate>Wed, 13 Mar 2019 21:42:12 GMT</pubDate><content:encoded><![CDATA[<p><em>This tutorial was updated on January 10, 2021 to generate a tone using Racket instead of merely wrapping a Linux-only command-line program called beep that controls the PC speaker. This should now make it possible to follow this tutorial on any OS supported by Racket. This tutorial can also be found in the <a target="_blank" href="https://github.com/goober99/lisp-gui-examples/blob/master/examples/racket/tutorial.md">GitHub repo</a> with the example code. Pull requests for improving the example and tutorial are welcome.</em></p>
<p>Racket is a Scheme-like dialect of Lisp that has a powerful cross-platform GUI
library built in. Instead of building yet another calculator, let's build a GUI
for generating a tone.</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/racket.png" alt="Screenshot" /></p>
<p>You'll need Racket installed, of course. It's available in the repositories of
most Linux distros, so just install it from your distro's repo. Then you're
ready to begin.</p>
<pre><code class="lang-scheme">#lang racket

(require racket/gui)
</code></pre>
<p>One of the strengths of Racket is the number of built-in libraries. We'll be
using the racket/gui library.</p>
<pre><code class="lang-scheme">; Main window
(define frame (new frame% [label "Bleep"]))

; Display GUI
(send frame show #t)
</code></pre>
<p>Racket's GUI library is object oriented. You create a window by instantiating
the <code>frame%</code> class. Identifiers ending with a percent is Racket's naming
convention for classes. You show the window by calling its <code>show</code> method. Now
let's add some additional widgets between creating the window and showing it.</p>
<pre><code class="lang-scheme">(define slider (new slider% [label #f]
                            [min-value 20]
                            [max-value 20000]
                            [parent frame]
                            [init-value 440]
                            [style '(horizontal plain)]
                            [vert-margin 25]
                            [horiz-margin 10]))
</code></pre>
<p>The range of frequencies audible by humans is typically between 20 Hz and 20
KHz (we lose the ability to hear some of those higher frequencies as we age).
The <a target="_blank" href="https://en.wikipedia.org/wiki/A440_(pitch_standard">musical note A above middle
C</a>) is 440 Hz. Since A4
serves as a general tuning standard, it seems like a sensible default, but if
you run the above in Racket, this is what you'll see:</p>
<p><img src="https://raw.githubusercontent.com/goober99/lisp-gui-examples/master/screenshots/racket-linearslider.png" alt="Slider" /></p>
<p>The scale of 20 to 20,000 is so large that 440 doesn't appear to move the
slider at all. Ideally, 440 would fall about the middle of the slider. To
achieve this, let's use a logarithmic scale.</p>
<p>I found a <a target="_blank" href="https://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249">Stack Overflow
answer</a>
on how to map a slider to a logarithmic scale. The code given in the answer is
JavaScript, but it was easy enough to port to Racket.</p>
<pre><code class="lang-scheme">; Scale used by slider
(define *min-position* 0)
(define *max-position* 2000)
; Range of frequencies
(define *min-frequency* 20)
(define *max-frequency* 20000)

; Logarithmic scale for frequency (so middle A [440] falls about in the middle)
; Adapted from https://stackoverflow.com/questions/846221/logarithmic-slider

(define min-freq (log *min-frequency*))
(define max-freq (log *max-frequency*))
(define frequency-scale (/ (- max-freq min-freq) (- *max-position* *min-position*)))
; Convert slider position to frequency
(define (position-&gt;frequency position)
  (inexact-&gt;exact (round (exp (+ min-freq (* frequency-scale (- position *min-position*)))))))
; Convert frequency to slider position
(define (frequency-&gt;position freq)
  (inexact-&gt;exact (round (/ (- (log freq) min-freq) (+ frequency-scale *min-position*)))))
</code></pre>
<p>I added some global parameters to the top of the script. The variable name
<code>*min-position*</code> is just a Lisp naming convention for global parameters. I came
up with the range of 0-2,000 by trial and error. It seemed to strike the best
balance between each step of the slider making a noticeable change to the
frequency while still allowing the user to narrow in on a specific frequency
with just the slider.</p>
<p>Then we create two functions: one that takes the position on the slider and
returns the frequency (<code>position-&gt;frequency</code>) and another that takes a
frequency and returns the position on the slider (<code>frequency-position</code>). Now
let's modify our <code>slider%</code> to use <code>frequency-&gt;position</code> to convert the
<code>init-value</code> to a slider position using our logarithmic scale.</p>
<pre><code class="lang-scheme">(define slider (new slider% [label #f]
                            [min-value *min-position*]
                            [max-value *max-position*]
                            [parent frame]
                            [init-value (frequency-&gt;position 440)]
                            [style '(horizontal plain)]
                            [vert-margin 25]
                            [horiz-margin 10]))
</code></pre>
<p>Underneath the slider is a text field showing the current frequency and buttons
to increase/decrease the frequency by one octave.</p>
<pre><code class="lang-scheme">(define frequency-pane (new horizontal-pane% [parent frame]
                                             [border 10]
                                             [alignment '(center center)]))
(define lower-button (new button% [parent frequency-pane]
                                  [label "&lt;"]))
(define frequency-field (new text-field% [label #f]
                                         [parent frequency-pane]
                                         [init-value "440"]
                                         [min-width 64]
                                         [stretchable-width #f]))
(define frequency-label (new message% [parent frequency-pane] [label "Hz"]))
(define higher-button (new button% [parent frequency-pane]
                                   [label "&gt;"]))
</code></pre>
<p>The <code>horizontal-pane%</code> is an invisible widget that helps with layout. At this
point, we are starting to have a nice looking interface, but it doesn't do
anything. If you click the buttons or slide the slider, nothing happens. The
widget classes accept a <code>callback</code> parameter that wires the widget up to a
function. If we add a callback function to the slider, that function will be
called each time the slider is moved.</p>
<pre><code class="lang-scheme">; Link slider to text field display of frequency
(define (adjust-frequency widget event)
  (send frequency-field set-value
    (~a (position-&gt;frequency (send widget get-value)))))
(define (adjust-slider entry event)
  (define new-freq (string-&gt;number (send entry get-value)))
  (send slider set-value
    (frequency-&gt;position (if new-freq new-freq *min-frequency*))))
</code></pre>
<p>A callback function takes two arguments: the first is the instance of the
object that called it and the second is the event type. The <code>text-field%</code>
expects a string, so we have to convert the number returned by
<code>position-&gt;frequency</code> to a string with <code>~a</code>. Next all there is to do is wire
these functions up to the widgets:</p>
<pre><code class="lang-scheme">(define slider (new slider% [label #f]
                            ...
                            [callback adjust-frequency]
                            ...))
...
(define frequency-field (new text-field% [label #f]
                                         ...
                                         [callback adjust-slider]
                                         ...))
</code></pre>
<p>Wire the buttons up to callback functions called <code>decrease-octave</code> and
<code>increase-octave</code>. An <a target="_blank" href="https://en.wikipedia.org/wiki/Octave">octave</a> is "the
interval between one musical pitch and another with double its frequency."</p>
<pre><code class="lang-scheme">; Set frequency slider and display
(define (set-frequency freq)
  (send slider set-value (frequency-&gt;position freq))
  (send frequency-field set-value (~a freq)))

; Buttons increase and decrease frequency by one octave
(define (adjust-octave modifier)
  (set-frequency (* (string-&gt;number (send frequency-field get-value)) modifier)))
(define (decrease-octave button event) (adjust-octave 0.5))
(define (increase-octave button event) (adjust-octave 2))
</code></pre>
<p>If you slide the slider, the text field updates accordingly. If you type a
number in the text field, the slider updates accordingly. All good, right? What
if a user (and you know they will) enters a number higher than 20,000 or a
letter?</p>
<p>The widgets included with Racket are pretty basic, but we can extend the
classes of the built-in widgets to create custom widgets. Let's extend the
<code>text-field%</code> class to create a new <code>number-field%</code> class. This class will have
two additional init variables that specify a <code>min-value</code> and <code>max-value</code> and
only allow numbers that fall within that range.</p>
<pre><code class="lang-scheme">; Extend the text-field% class to validate data when field loses focus. Field
; should contain only numbers within allowed range. Otherwise, set to min.
(define number-field%
  (class text-field%
    ; Add init variables to define allowed range
    (init min-value max-value)
    (define min-allowed min-value)
    (define max-allowed max-value)
    (super-new)
    (define/override (on-focus on?)
      (unless on?
        (define current-value (string-&gt;number (send this get-value)))
        (unless (and current-value
                     (&gt;= current-value min-allowed)
                     (&lt;= current-value max-allowed))
          (send this set-value (~a min-allowed))
          ; Also reset slider position to make sure it still matches display
          (send slider set-value (string-&gt;number (send frequency-field get-value))))))))
</code></pre>
<p>Then we can replace our <code>text-field%</code> with a <code>number-field%</code>.</p>
<pre><code class="lang-scheme">(define frequency-field (new number-field% [label #f]
                                           [parent frequency-pane]
                                           [min-value *min-frequency*]
                                           [max-value *max-frequency*]
                                           [callback adjust-slider]
                                           [init-value "440"]
                                           [min-width 64]
                                           [stretchable-width #f]))
</code></pre>
<p>Let's use this <code>number-field%</code> again to create a field to specify the duration
of the beep in milliseconds:</p>
<pre><code class="lang-scheme">(define control-pane (new horizontal-pane% [parent frame]
                                           [border 25]
                                           [spacing 25]))
(define duration-pane (new horizontal-pane% [parent control-pane]))
(define duration-field (new number-field% [label "Duration "]
                                          [parent duration-pane]
                                          [min-value 1]
                                          [max-value 600000] ; 10 minutes
                                          [init-value "200"]
                                          [min-width 120]))
</code></pre>
<p>Frequency is rather abstract. Let's also give the user the ability to select a
musical note. We can store the corresponding frequencies for A4-G4 in a hash
table.</p>
<pre><code class="lang-scheme">; Notes -&gt; frequency (middle A-G [A4-G4])
; http://pages.mtu.edu/~suits/notefreqs.html
(define notes (hash "A" 440.00
                    "B" 493.88
                    "C" 261.63
                    "D" 293.66
                    "E" 329.63
                    "F" 349.23
                    "G" 292.00))
</code></pre>
<p>We'll give the user a drop-down menu. Whenever a note is selected from the
drop-down menu, we'll look up the frequency in the hash table and set it using
the <code>set-frequency</code> helper function we created for the octave buttons.</p>
<pre><code class="lang-scheme">; Set frequency to specific note
(define (set-note choice event)
  (set-frequency (hash-ref notes (send choice get-string-selection))))
(define note (new choice% [label "♪ "]
                          [choices '("A" "B" "C" "D" "E" "F" "G")]
                          [parent control-pane]
                          [callback set-note]))
</code></pre>
<p>Finally, let's make some noise.</p>
<pre><code class="lang-scheme">(require rsound)

; Generate a tone using RSound
; Explicitly set RSound sample rate in case differs by platform/version
(default-sample-rate 44100)
(define (generate-tone button event)
  (play (make-tone (string-&gt;number (send frequency-field get-value))
                   0.5
                   ; Duration in samples at sample rate of 44.1 kHz
                   (inexact-&gt;exact (* 44.1 (string-&gt;number (send duration-field get-value)))))))
</code></pre>
<p>We'll use the Racket <a target="_blank" href="https://docs.racket-lang.org/rsound/index.html">RSound</a>
package to generate the tone. This package isn't bundled with Racket, but you
can install it with the <code>raco</code> utility that comes with Racket (<code>raco pkg
install rsound</code>). Wire this up to a button between the duration and note
selector, and you're ready to make some noise.</p>
<pre><code class="lang-scheme">(define play-button (new button% [parent control-pane]
                                 [label "Play"]
                                 [callback generate-tone]))
</code></pre>
<p><em>You can check out the entire example on <a target="_blank" href="https://github.com/goober99/lisp-gui-examples">GitHub</a>. This started as a personal learning project to explore the state of GUI programming in Lisp and has become a series of tutorials on building GUIs with various dialects of Lisp.</em></p>
]]></content:encoded></item></channel></rss>