From anders at avinjar.no Fri Oct 4 02:54:24 2024 From: anders at avinjar.no (Anders Vinjar) Date: Fri, 04 Oct 2024 11:54:24 +0200 Subject: [CM] snd (jack) dac output channels > 2 ? Message-ID: <87ttdsfb1r.fsf@avinjar.no> Hi. I might be missing something obvious: using Jack, is it possible to run - or configure - snd to play more than 2 output channels? -anders From tito.01beta at gmail.com Sat Oct 5 00:00:55 2024 From: tito.01beta at gmail.com (Tito Latini) Date: Sat, 5 Oct 2024 09:00:55 +0200 Subject: [CM] snd (jack) dac output channels > 2 ? In-Reply-To: <87ttdsfb1r.fsf@avinjar.no> References: <87ttdsfb1r.fsf@avinjar.no> Message-ID: Set the environment variable SNDLIB_NUM_JACK_CHANNELS, for example: shell> SNDLIB_NUM_JACK_CHANNELS=8 snd or in ~/.bashrc: export SNDLIB_NUM_JACK_CHANNELS=8 Il giorno ven 4 ott 2024 alle ore 11:54 Anders Vinjar ha scritto: > Hi. > > I might be missing something obvious: using Jack, is it possible to > run - or configure - snd to play more than 2 output channels? > > -anders > _______________________________________________ > Cmdist mailing list > Cmdist at ccrma.stanford.edu > https://cm-mail.stanford.edu/mailman/listinfo/cmdist > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chohag at jtan.com Sat Oct 5 15:08:56 2024 From: chohag at jtan.com (chohag at jtan.com) Date: Sat, 05 Oct 2024 23:08:56 +0100 Subject: [CM] AOT compilation for cload.scm Message-ID: <202410052208.495M8wpM532280@zeus.jtan.com> Hi, I've made an adaptation of cload.scm that generates code sepatately so that I can compile extension libraries ahead of time during the project build phase. It's incomplete, not least because the new functions I've created have been split off from c-define with whatever data I needed at the time without a thought for making a clean design. But it works and I'm using it so I'm posting it here in case it's useful. The original c-define API remains unchanged and there are no real changes to the implementation except this one: - (format p "#include <~A>~%" header)) + (if (string? header) + (format p "#include \"~A\"~%" header) + (format p "#include <~A>~%" (symbol->string header)))) Everything else is just shuffling things around or breaking functions into pieces. I've tried to keep the original spacing intact. I use it like this: (load "cload.scm") (unless (defined? '*mylib*) (define *mylib* (with-let (sublet (unlet)) (set! *libraries* (cons (cons "mylib.scm" (curlet)) *libraries*)) (set! *cload-library-name* "*mylib*") (if (not *cload-generate-only*) ; negative so all the C is last (c-load "s7lib_mylib") (c-generate-source "s7lib_mylib" "s7lib_mylib_init" (list 'assert.h "mylib.h") ((C-function in-C etc.)))) (curlet)))) *mylib* And in a Makefile: s7lib_mylib.c: s7run mylib.scm ./s7run '(define *cload-generate-only* #t)' mylib.scm > s7lib_mylib.c @[ -s s7lib_mylib.c ] || ! rm -f s7lib_mylib.c s7lib_mylib.so: s7lib_mylib.o ${LINK.c} s7lib_mylib.o -shared -o s7lib_mylib.so There are five new functions in addition to c-define. (c-load env libname initname) This doesn't match (load) which has env last but initname should be optional. (c-init-name libname) Appends "_init" to libname. (c-create-file libname initname headers c-body prefix) (c-generate-source libname initname headers c-body prefix) These should match the c-define calling convention: (c-define env body prefix headers cflags ldflags outname) (c-compile cname oname soname cflags ldflags) Used internally by cload.scm. At some point I hope to come back to this module and improve the design but for now I'm getting back to the reason I shaved this yak. In the meantime here it is, and if anyone can come up with a better interface then please do. Cheers, Matthew -------------- next part -------------- --- ../s7/cload.scm Sat Oct 5 22:10:09 2024 +++ cload.scm Sat Oct 5 22:11:15 2024 @@ -118,17 +118,14 @@ (defvar c-define-output-file-counter 0) ; ugly, but I can't find a way around this (dlopen/dlsym stupidity) +(defvar *cload-generate-only* #f) -;;; to place the new function in the caller's current environment, we need to pass the environment in explicitly: -(define-macro (c-define . args) - (cons 'c-define-1 (cons '(curlet) args))) +(define* (c-create-file library (init-name (c-init-name library)) (headers ()) c-body (prefix "")) + (define p (open-output-file (string-append library ".c"))) + (c-generate-source library init-name headers c-body prefix p) + (close-output-port p)) - -(define* (c-define-1 cur-env function-info (prefix "") (headers ()) (cflags "") (ldflags "") output-name) - ;; write a C shared library module that links in the functions in function-info - ;; function info is either a list: (return-type c-name arg-type) or a list thereof - ;; the new functions are placed in cur-env - +(define* (c-generate-source library (init-name (c-init-name library)) (headers ()) c-body (prefix "") (port ())) (define handlers (list '(integer s7_is_integer s7_integer s7_make_integer s7_int) '(boolean s7_is_boolean s7_boolean s7_make_boolean bool) '(real s7_is_real s7_number_to_real_with_caller s7_make_real s7_double) @@ -205,20 +202,8 @@ ((c-pointer?) #\x) (else #\t))) - (set! c-define-output-file-counter (+ c-define-output-file-counter 1)) - (let ((file-name (string-append *cload-directory* - (if (and (> (length *cload-directory*) 0) - (not (char=? (string-ref *cload-directory* (- (length *cload-directory*) 1)) #\/))) - "/" "") - (or output-name (format #f "temp-s7-output-~D" c-define-output-file-counter))))) - (let ((c-file-name (string-append file-name ".c")) - (o-file-name (string-append file-name ".o")) - (so-file-name (string-append file-name ".so")) - (init-name (if (string? output-name) - (string-append output-name "_init") - (string-append "init_" (number->string c-define-output-file-counter)))) - (functions ()) + (let ((functions ()) (constants ()) (macros ()) ; these are protected by #ifdef ... #endif (inits ()) ; C code (a string in s7) inserted in the library initialization function @@ -278,7 +263,7 @@ (define (initialize-c-file) ;; C header stuff - (set! p (open-output-file c-file-name)) + (set! p port) (format p "#include ~%") (format p "#include ~%") (format p "#include ~%") @@ -286,7 +271,9 @@ (format p "#include <~A>~%" headers) (for-each (lambda (header) - (format p "#include <~A>~%" header)) + (if (string? header) + (format p "#include \"~A\"~%" header) + (format p "#include <~A>~%" (symbol->string header)))) headers)) (format p "#include \"s7.h\"~%~%") (format p "static s7_pointer fsym, s7_F, s7_unspec, ffunc, c_pointer_string, string_string, character_string, boolean_string, real_string, complex_string, integer_string;~%")) @@ -507,9 +494,9 @@ (format p "~A~A~A" (cdr sym) (if (< loc len) (values "," " ") (values ";" #\newline))) (set! loc (+ loc 1))) type-symbols))) - (newline p) + (format p "~%") - (display (get-output-string pp) p) + (format p (get-output-string pp)) (close-output-port pp) ;; now the init function @@ -578,7 +565,7 @@ (reverse inits)) (when (pair? type-symbols) - (newline p) + (format p "~%") (for-each (lambda (sym) (format p " ~S = s7_make_symbol(sc, ~S);~%" (cdr sym) (symbol->string (car sym)))) @@ -676,52 +663,8 @@ (format p " s7_set~A_function(sc, s7_name_to_value(sc, ~S), ~A~A);~%" (caddr f) (cadr f) (car f) (caddr f)))) double-int-funcs)) - (format p "}~%") - (close-output-port p) + (format p "}~%")) - (unless (or (file-exists? "s7.h") - (not (pair? *load-path*))) - (set! *cload-cflags* (append *cload-cflags* (format #f " -I~A" (car *load-path*))))) - - ;; now we have the module .c file -- make it into a shared object - - (cond ((provided? 'osx) - ;; I assume the caller is also compiled with these flags? - (system (format #f "~A -c ~A -o ~A ~A ~A" - *cload-c-compiler* c-file-name o-file-name *cload-cflags* cflags)) - (system (format #f "~A ~A -o ~A -dynamic -bundle -undefined suppress -flat_namespace ~A ~A" - *cload-c-compiler* o-file-name so-file-name *cload-ldflags* ldflags))) - - ((provided? 'freebsd) - (system (format #f "cc -fPIC -c ~A -o ~A ~A ~A" - c-file-name o-file-name *cload-cflags* cflags)) - (system (format #f "cc ~A -shared -o ~A ~A ~A" - o-file-name so-file-name *cload-ldflags* ldflags))) - - ((provided? 'openbsd) - (system (format #f "~A -fPIC -c ~A -o ~A ~A ~A" - *cload-c-compiler* c-file-name o-file-name *cload-cflags* cflags)) - (system (format #f "~A ~A -shared -o ~A ~A ~A" - *cload-c-compiler* o-file-name so-file-name *cload-ldflags* ldflags))) - - ((provided? 'sunpro_c) ; just guessing here... - (system (format #f "cc -c ~A -o ~A ~A ~A" - c-file-name o-file-name *cload-cflags* cflags)) - (system (format #f "cc ~A -G -o ~A ~A ~A" - o-file-name so-file-name *cload-ldflags* ldflags))) - - ((or (provided? 'mingw) (provided? 'msys2)) ; from chai xiaoxiang - ;; you'll need dlfcn which can be installed with pacman, and remember to build s7 with -DWITH_C_LOADER=1 - ;; in msys2: gcc s7.c -o s7 -DWITH_MAIN -DWITH_C_LOADER=1 -I. -O2 -g -ldl -lm -Wl,-export-all-symbols,--out-implib,s7.lib - (system (format #f "gcc ~A s7.lib -shared -o ~A -I. ~A ~A" - c-file-name so-file-name cflags ldflags))) - - (else ; linux netbsd - (system (format #f "~A -fPIC -c ~A -o ~A ~A ~A" - *cload-c-compiler* c-file-name o-file-name *cload-cflags* cflags)) - (system (format #f "~A ~A -shared -o ~A ~A ~A" - *cload-c-compiler* o-file-name so-file-name *cload-ldflags* ldflags))))) - (define handle-declaration (let () (define (add-one-constant type name) @@ -765,6 +708,95 @@ (error 'wrong-type-arg "~S (func arg to handle-declaration in cload.scm) should be a pair" func))))) + (initialize-c-file) + + (if (and (pair? (cdr c-body)) + (symbol? (cadr c-body))) + (handle-declaration c-body) + (for-each handle-declaration c-body)) + + (end-c-file))) + + +(define (c-compile c-file-name o-file-name so-file-name cflags ldflags) + (unless (or (file-exists? "s7.h") + (not (pair? *load-path*))) + (set! *cload-cflags* (append *cload-cflags* (format #f " -I~A" (car *load-path*))))) + + ;; now we have the module .c file -- make it into a shared object + + (cond ((provided? 'osx) + ;; I assume the caller is also compiled with these flags? + (system (format #f "~A -c ~A -o ~A ~A ~A" + *cload-c-compiler* c-file-name o-file-name *cload-cflags* cflags)) + (system (format #f "~A ~A -o ~A -dynamic -bundle -undefined suppress -flat_namespace ~A ~A" + *cload-c-compiler* o-file-name so-file-name *cload-ldflags* ldflags))) + + ((provided? 'freebsd) + (system (format #f "cc -fPIC -c ~A -o ~A ~A ~A" + c-file-name o-file-name *cload-cflags* cflags)) + (system (format #f "cc ~A -shared -o ~A ~A ~A" + o-file-name so-file-name *cload-ldflags* ldflags))) + + ((provided? 'openbsd) + (system (format #f "~A -fPIC -c ~A -o ~A ~A ~A" + *cload-c-compiler* c-file-name o-file-name *cload-cflags* cflags)) + (system (format #f "~A ~A -shared -o ~A ~A ~A" + *cload-c-compiler* o-file-name so-file-name *cload-ldflags* ldflags))) + + ((provided? 'sunpro_c) ; just guessing here... + (system (format #f "cc -c ~A -o ~A ~A ~A" + c-file-name o-file-name *cload-cflags* cflags)) + (system (format #f "cc ~A -G -o ~A ~A ~A" + o-file-name so-file-name *cload-ldflags* ldflags))) + + ((or (provided? 'mingw) (provided? 'msys2)) ; from chai xiaoxiang + ;; you'll need dlfcn which can be installed with pacman, and remember to build s7 with -DWITH_C_LOADER=1 + ;; in msys2: gcc s7.c -o s7 -DWITH_MAIN -DWITH_C_LOADER=1 -I. -O2 -g -ldl -lm -Wl,-export-all-symbols,--out-implib,s7.lib + (system (format #f "gcc ~A s7.lib -shared -o ~A -I. ~A ~A" + c-file-name so-file-name cflags ldflags))) + + (else ; linux netbsd + (system (format #f "~A -fPIC -c ~A -o ~A ~A ~A" + *cload-c-compiler* c-file-name o-file-name *cload-cflags* cflags)) + (system (format #f "~A ~A -shared -o ~A ~A ~A" + *cload-c-compiler* o-file-name so-file-name *cload-ldflags* ldflags))))) + + +(define-macro (c-load . args) + `(,c-load-1 ,(curlet) , at args)) + +(define* (c-load-1 env library (init (c-init-name library))) + (varlet env 'init_func (string->symbol init)) + (load (string-append library ".so") env)) ;; Did you call yours dylib for no reason? So? + + +;;; to place the new function in the caller's current environment, we need to pass the environment in explicitly: +(define-macro (c-define . args) + (cons 'c-define-1 (cons '(curlet) args))) + + +(define (c-init-name output-name) + (if (string? output-name) + (string-append output-name "_init") + (string-append "init_" (number->string c-define-output-file-counter)))) + + +(define* (c-define-1 cur-env function-info (prefix "") (headers ()) (cflags "") (ldflags "") output-name) + ;; write a C shared library module that links in the functions in function-info + ;; function info is either a list: (return-type c-name arg-type) or a list thereof + ;; the new functions are placed in cur-env + + (let ((file-name (string-append *cload-directory* + (if (and (> (length *cload-directory*) 0) + (not (char=? (string-ref *cload-directory* (- (length *cload-directory*) 1)) #\/))) + "/" "") + (or output-name (format #f "temp-s7-output-~D" c-define-output-file-counter))))) + (let ((c-file-name (string-append file-name ".c")) + (o-file-name (string-append file-name ".o")) + (so-file-name (string-append file-name ".so")) + (init-name (c-init-name output-name))) + ;; c-define-1 (called in c-define macro above) (unless (and output-name (file-exists? c-file-name) @@ -773,23 +805,15 @@ (>= (file-mtime so-file-name) (file-mtime c-file-name)) (not (and (file-exists? (port-filename)) (< (file-mtime so-file-name) (file-mtime (port-filename)))))) - (format *stderr* "writing ~A~%" c-file-name) ;; write a new C file and compile it - (initialize-c-file) - - (if (and (pair? (cdr function-info)) - (symbol? (cadr function-info))) - (handle-declaration function-info) - (for-each handle-declaration function-info)) - - (end-c-file) + (format *stderr* "writing ~A~%" c-file-name) + (c-create-file output-name init-name headers function-info prefix) ;; (map string->symbol headers) + (c-compile c-file-name o-file-name so-file-name cflags ldflags) (delete-file o-file-name)) ;; load the object file, clean up - (varlet cur-env 'init_func (string->symbol init-name)) (format *stderr* "loading ~A~%" so-file-name) - (load so-file-name cur-env)))) - + (c-load-1 cur-env output-name init-name)))) #| (let ((cd (symbol "complex double")) From anders at avinjar.no Sun Oct 6 05:08:29 2024 From: anders at avinjar.no (Anders Vinjar) Date: Sun, 06 Oct 2024 14:08:29 +0200 Subject: [CM] snd (jack) dac output channels > 2 ? In-Reply-To: (Tito Latini's message of "Sat, 5 Oct 2024 09:00:55 +0200") References: <87ttdsfb1r.fsf@avinjar.no> Message-ID: <87h69pv3gi.fsf@avinjar.no> Thanks! From anders at avinjar.no Sun Oct 6 05:44:02 2024 From: anders at avinjar.no (Anders Vinjar) Date: Sun, 06 Oct 2024 14:44:02 +0200 Subject: [CM] snd (jack) dac output channels > 2 ? In-Reply-To: (Tito Latini's message of "Sat, 5 Oct 2024 09:00:55 +0200") References: <87ttdsfb1r.fsf@avinjar.no> Message-ID: <87cykdv1t9.fsf@avinjar.no> Hi Bill, > ? shell> SNDLIB_NUM_JACK_CHANNELS=8 snd suggest you include something like that in the section about environment variables in grfsnd.html: 874d873 < SNDLIB_NUM_JACK_CHANNELS number of output output channels -anders From bil at ccrma.Stanford.EDU Sun Oct 6 10:28:41 2024 From: bil at ccrma.Stanford.EDU (bil at ccrma.Stanford.EDU) Date: Sun, 06 Oct 2024 10:28:41 -0700 Subject: [CM] =?utf-8?q?snd_=28jack=29_dac_output_channels_=3E_2_=3F?= In-Reply-To: <87cykdv1t9.fsf@avinjar.no> References: <87ttdsfb1r.fsf@avinjar.no> <87cykdv1t9.fsf@avinjar.no> Message-ID: <43ab9b554e7af117c4a5cf3974d2c79f@ccrma.stanford.edu> > shell> SNDLIB_NUM_JACK_CHANNELS=8 snd Right -- thanks for reminding me. From chohag at jtan.com Wed Oct 9 15:27:52 2024 From: chohag at jtan.com (chohag at jtan.com) Date: Wed, 09 Oct 2024 23:27:52 +0100 Subject: [CM] s7_complex in C++ Message-ID: <202410092227.499MRtMf273221@zeus.jtan.com> Hi, I am linking s7 with a C++ library and the compiler now balks on the new s7_complex definition: ./s7.h:351:14: warning: 's7_complex_vector_ref' has C-linkage specified, but returns user-defined type 's7_complex' (aka 'complex') which is incompatible with C [-Wreturn-type-c-linkage] s7_complex s7_complex_vector_ref(s7_pointer vec, s7_int index); ^ ./s7.h:352:14: warning: 's7_complex_vector_set' has C-linkage specified, but returns user-defined type 's7_complex' (aka 'complex') which is incompatible with C [-Wreturn-type-c-linkage] s7_complex s7_complex_vector_set(s7_pointer vec, s7_int index, s7_complex value); ^ This is "solved" by the attached patch which changes the return type of the offending functions to a s7_complex*. This makes the compiler happy but obviously this is not the right solution. I know it's only a warning but a warning is a sign that the compiler vendor is going to quietly make it undefined behaviour soon and I don't know C++ well enough to rewrite the macros around the s7_complex definition into something the compiler would like. Matthew -------------- next part -------------- A non-text attachment was scrubbed... Name: s7-complex.diff Type: text/x-c Size: 1726 bytes Desc: s7-complex.diff URL: From bil at ccrma.Stanford.EDU Wed Oct 9 16:03:02 2024 From: bil at ccrma.Stanford.EDU (bil at ccrma.Stanford.EDU) Date: Wed, 09 Oct 2024 16:03:02 -0700 Subject: [CM] =?utf-8?q?s7=5Fcomplex_in_C++?= In-Reply-To: <202410092227.499MRtMf273221@zeus.jtan.com> References: <202410092227.499MRtMf273221@zeus.jtan.com> Message-ID: Which C++ compiler are you using? The code works in g++. I'd try commenting out the typedef for s7_complex in the __cplusplus section (i.e. maybe your compiler wants the C form of the typedef). From bil at ccrma.Stanford.EDU Thu Oct 10 06:27:28 2024 From: bil at ccrma.Stanford.EDU (bil at ccrma.Stanford.EDU) Date: Thu, 10 Oct 2024 06:27:28 -0700 Subject: [CM] Snd 24.8 Message-ID: <824b410d5896a7309d8c0589de136328@ccrma.stanford.edu> Snd 24.8 s7: divided s7.html into 3 files: s7.html, s7-ffi.html, and s7-scm.html. added swap! to stuff.scm checked: sbcl 2.4.9 Thanks!: Daniel Hensel, Tito Latini From chohag at jtan.com Fri Oct 11 10:38:59 2024 From: chohag at jtan.com (chohag at jtan.com) Date: Fri, 11 Oct 2024 18:38:59 +0100 Subject: [CM] s7_complex in C++ In-Reply-To: References: <202410092227.499MRtMf273221@zeus.jtan.com> Message-ID: <202410111739.49BHd2ha128651@zeus.jtan.com> bil at ccrma.Stanford.EDU writes: > Which C++ compiler are you using? The code works in g++. > I'd try commenting out the typedef for s7_complex in the > __cplusplus section (i.e. maybe your compiler wants the C > form of the typedef). $ c++ --version OpenBSD clang version 16.0.6 Target: amd64-unknown-openbsd7.6 Thread model: posix InstalledDir: /usr/bin Aide-m?moire: #if (!__TINYC__) #if __cplusplus #include typedef std::complex s7_complex; #else #include typedef double complex s7_complex; #endif #else typedef double s7_complex; #endif If I change line 21 to #if __cplusplus && 0 then I get: ./s7.h:39:27: error: expected ';' after top level declarator typedef double complex s7_complex; ^ ; There are two problems here. First because s7.h declares functions with C linkage, s7_complex' expansion to std::complex cannot be used in a function signature. Second C++ is doing magic. When is included, rather than actually including complex.h, it knows better and reverts to its own imagination which doesn't have a definition for complex. It also doesn't bother declaring any of the functions that are declared by that file. Because, again, the compiler knows better than us that we don't want to be explicit about what types our functions take but do love tracking down the precise collusion of operator or function overloading that happen to be in play in *this* line of code. If I change the inclusion to "/usr/include/complex.h" then C++'s sleight of hand is thwarted and we actually include the file we asked for and 'double complex' is a valid type name again. I understand that this behaviour is blessed by the standards committee. I expect there is a right way to include C-linkage complex-returning functions in a C++ compiler but I don't know what it is. There are no useful examples in /usr/include/complex.h because C++ ignores that. However this works well enough in a C header included from C++: typedef struct { double r, i; } s7_complex; But then s7.o cannot be built by a C++ compiler. On the other hand it apparently can't be built with this C++ compiler anyway: s7.c:13811:84: error: invalid operands to binary expression ('_Complex double' and 's7_complex' (aka 'complex')) static s7_complex casin(s7_complex z) {return(-s7_complex_i * clog(s7_complex_i * z + csqrt(1.0 - z * z)));} ~~~~~~~~~~~~ ^ ~ Matthew From bil at ccrma.Stanford.EDU Fri Oct 11 12:19:24 2024 From: bil at ccrma.Stanford.EDU (bil at ccrma.Stanford.EDU) Date: Fri, 11 Oct 2024 12:19:24 -0700 Subject: [CM] =?utf-8?q?s7=5Fcomplex_in_C++?= In-Reply-To: <202410111739.49BHd2ha128651@zeus.jtan.com> References: <202410092227.499MRtMf273221@zeus.jtan.com> <202410111739.49BHd2ha128651@zeus.jtan.com> Message-ID: Good grief, what a nightmare. It looks to me like s7 can be compiled by gcc/clang (C compilers), and g++ (I tried version 12.2.0 and 14.2.1), but not by clang++ (tried versions 12.0.0 and 18.1.8). Getting gcc/g++ to work with complex numbers was tricky, but clang++ has apparently decided to make it impossible. I'll have to poke around online to see what the work-around might be. For now, it might work to comment out the s7.h entries for the complex vector functions (but I ran into some other problem when I tried that). Also I had to change noreturn to no_return for clang++. From chohag at jtan.com Sun Oct 13 11:31:27 2024 From: chohag at jtan.com (chohag at jtan.com) Date: Sun, 13 Oct 2024 19:31:27 +0100 Subject: [CM] Announcing complete-ish S7 interface to OpenGL Message-ID: <202410131831.49DIVT44305020@zeus.jtan.com> Hi, I have previously posted here some of the work I'm doing to create S7 wrappers for graphical libraries. It has now reached a stage where I can collect it together and polish it into a moderately coherent standalone project, stogl. https://codeberg.org/ChoHag/stogl It is far from finished, in fact the wrappers themselves are barely begun. Really it's just a scaffold linking together the various parts I intend to use. "Complete" refers to the structure not the content. Sorry. But it's a scaffold I can use to do programming with rather than making scaffolding. It's stable and it works. It even has a little bit of documentation. I don't have to write in C (much). There are examples that draw a triangle, a rotating reflecting cube with a texture and a clone of glxgears, written entirely in S7 scheme. Unlike my earlier code the namespaces have been brought under some control. The form it takes is a normal unix library that just links to SDL and OpenGL and co-ordinates the launch of a thread running OpenGL instructions in an endless loop. This library can be installed and used from C as is. It is also wrapped up for S7 independently. Whether from S7 or C the programmer is expected to construct a list of draw instructions for each frame and assign it to a location where they will be carried out in the next OpenGL thread loop (or discarded if another frame is prepared before OpenGL is ready). The changes I previously made to cload.scm are also included with a couple of different ways of making use of them; see the Makefile. It was tested on Linux a while ago but my Linux box is currently out of commission so I will get to that as soon as I can. Hopefully there are no problems but they should be trivial. It builds as-is on OpenBSD with the requisite packages installed. It's an itch I needed to scratch so I'll be improving it as and when: there is a lot of missing functionality in the S7 interfaces which will I'll add when I need it. And of course the documentation is even less complete than everything else. And finally if you use it and have questions (or patches!) please get in touch with me directly. This isn't an S7 project it's just something I'm making which uses it, so there is no need to pollute this mailing list with it any further. Cheers, Matthew