call-as-xtlang, xtmX, $ and Scheme

17 views
Skip to first unread message

geor...@bigpond.net.au

unread,
Nov 18, 2021, 2:49:37 AM11/18/21
to Extempore
In ~/extempore/examples/external/granulator.xtm I find 11 occurrences of xtmX.
So I hunted around trying to find what that meant.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
In extempore/runtime/llvmti.xtm at line 11895 we have a macro definition
for call-as-xtlang
In the same file at line 11921, 11922
we have:
(define xtmX call-as-xtlang) 
(define $ call-as-xtlang)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

In extempore/examples/core/audio_101.xtm
at  line 81 to 105 we have:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; a simple example of "event" level control
;;
;; or how to to control DSP code from inside
;; a scheme temporal recursion


;; modify one of the examples from above
;; adding freq1 and freq2 into closure environment
(bind-func dsp
  (let ((osc1 (osc_c 0.0))
        (osc2 (osc_c 0.0))
        (freq1 220.0)
        (freq2 220.0))
    (lambda (in:SAMPLE time:i64 channel:i64 data:SAMPLE*)
      (cond ((= channel 1) (osc1 0.3 freq1))
            ((= channel 0) (osc2 0.3 freq2))
            (else 0.0)))))

;; write accessor function for modification
;; of closure slots freq1 and freq2
(bind-func change_freq
  (lambda (freq1 freq2)
    (dsp.freq1:SAMPLE freq1)
    (dsp.freq2:SAMPLE freq2)))

The example goes on to make a loop to change the frequencies randomly.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

I notice that you can alter the dsp.freq1 and dsp.freq2 'by hand'
using four different methods:
($ (change_freq 330.0 335.0))  ; using $
(xtmX (change_freq 430.0 230.0)) ; using xtmX
(call-as-xtlang (change_freq 135.0 140.0)) ; using call-as-xtlang
(change_freq 440.0 445.0) ;; Maybe no need for the $ at all. Always?

I have a vague recall that 4th version above was a newer addition to the code
so the older versions are a legacy.
But I realise this is to do with the interaction between xtlang and Scheme.
Will the 4th version above ALWAYS work? Could the $ versions and the xtmX versions be
purged from all extempore code?
Would it be neater to leave out the various call-as-xtlang forms altogether?
Would extempore/runtime/llvmti.xtm compile if lines such as:
line 31 (xtmX (gran1.iot 2000))     ;; inter offset time between grains
be replaced by:
(gran1.iot 2000)     ;; inter offset time between grains

I haven't tried it ......... 
Still plugging away trying to understand something of extempore .....

Regards
George

geor...@bigpond.net.au

unread,
Nov 18, 2021, 5:08:19 PM11/18/21
to Extempore
Well I've just had another look at Scheme-xtlang interop
which makes things a little clearer maybe?
I realise I'm not quite understanding this thing. So I'm just thinking aloud!
I wonder if the (change_freq 440.0 445.0) above is solidly  in scheme land. The change-freq function here is the scheme version
of the the one defined by:
(bind-func change_freq
  (lambda (freq1 freq2)
    (dsp.freq1:SAMPLE freq1)
    (dsp.freq2:SAMPLE freq2)))

And the purely scheme version (change_freq 440.0 445.0) works because it is not attempting to call another xtlang function
but simply supplying a couple of typed variable values to the dsp closure.

Which is quite different from the failed  (test_apply squarer 2.0) in the interop example where
the scheme version of test-apply (automatically created when the xtlang version of test-apply was created)
is attempting to address the scheme version of squarer rather than the scheme cptr version.
So the ($ ()) is saying 'stay in xtlang land'  ???

The interop doc makes a couple of points about 'potentially confusing things'.
Item 2: its important to understand when you are in a Scheme context vs an xtlang context. If you are typing into your text editor, and you are on a new line, and you type an opening ( then what comes next should be a Scheme function.

If I type a ( and then the next thing is a 'bind' or a '$' or 'xtmX' wouldn't I be in xtlang? 
If the next after ( is a 'define'' wouldn't I be in scheme?

Regards
George

Toby Gifford

unread,
Nov 18, 2021, 6:02:57 PM11/18/21
to extemp...@googlegroups.com
One of the tricky things about learning extempore is that there are two quite separate languages: scheme and xtlang, which both look similar, and sometimes it can be confusing knowing which language you are using at any given point.

As I understand it, the REPL itself is a scheme interpreter, so that top-level s-expressions are always scheme - but may tell scheme that from a certain point forward it should treat the rest of the s-expression as a literal string to feed into the xtlang compiler.
Sounds like a mouthful!  More simply, once you write
(bind-func myfunc
...
The ... gets passed as a literal string to the xtlang compiler.  

The only way to actually interact with xtlang is through the scheme repl.  So even when you call
(myfunc)
you are actually calling a scheme wrapper function called myfunc which calls the xtlang function myfunc. However if you call myfunc in the middle of some other xtlang code then it is just the xtlang myfunc.

There are a couple of other keywords that drop one into an xtlang context, such as bind-var, Generally if it's got bind in the name, the arguments following will be looked up in xtlang context.
But conceptually the primary way of 'dropping' into an xtlang context is bind-func. This means, for example, if you want to print the value of a variable defined in xtlang (perhaps via bind-var) then you need to create a function that prints it, and call that function using the automatically created scheme wrapper. Originally this was the way to do it.

After a while, it became clear that it would be convenient to have a quicker way of doing this, so the call-as-xtlang macro (at least I think it is a macro) was introduced.  It was found to be so convenient that a shorthand alias for it was created xtmX, and again because this got used so much it got abbreviated even more to $.  Under the hood these (identical) convenience functions create an anonymous function (well, not actually anonymous but the name is hidden from you) and call it.


--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelan...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/extemporelang/f8e92633-0264-4713-b852-2fed61b976fbn%40googlegroups.com.

Ben Swift

unread,
Nov 18, 2021, 7:13:36 PM11/18/21
to extemp...@googlegroups.com
Hi Toby

> Sounds like a mouthful! More simply, once you write
> (bind-func myfunc
> ...
> )
> The ... gets passed as a literal string to the xtlang compiler.

One small nit-pick - it's still handled as an s-exp (a Scheme list) for a fair
bit of its journey through the compiler. Things only start to get really stringy
once you get into the part where the LLVM IR is emitted. Not that that's a
distinction which (should) leak out to the users :)

Cheers,
Ben

George Wright

unread,
Nov 19, 2021, 9:00:01 PM11/19/21
to extemp...@googlegroups.com
Toby & Ben
Thanks for your patient explanation.
I like your picture of the xtlang code heading off to a separate compiler. I think I can hang onto that image when working on this stuff. I see repeated notes in the docs to the effect that we are dealing with two separate languages.
I guess a rule-of-thumb might be just to avoid mixing them where possible.

By the way, I did try searching through code to find some way of querying the ’type’ of an xtlang function.
I found some versions of ‘get-type’ but they seem to be in compiler code which Is foreign country for me at the moment.
I wonder of there is a simple way of getting a return on the type of something in xtlang other than the console readout at compile time.

Regards
George

George Wright



Reply all
Reply to author
Forward
0 new messages