Csound-x

Table of Contents


Next: , Previous: (dir), Up: (dir)

Csound-x documentation

last updated 13 July 2015


Next: , Previous: Top, Up: Top

About this documentation

... well it is a work in progress. Feedback is welcome !

Stef

hepta@zogotounga.net


Next: , Previous: About this documentation, Up: Top

Overview

Csound-x is a set of editing modes and libraries intended to compose music for Csound without leaving Emacs. Its main purpose is to propose a full-featured textual front-end for Csound.

It is developed using GNU Emacs 23.

GNU Emacs 21 and 22 should be supported but this is not tested. XEmacs is not supported.


Editing & compiling Csound documents

Csound-x provides indentation and fontification for scores and orchestras. Direct access to the Csound documentation allows insertion of opcode templates.

A CSD can be generated from a simple text containing a score and an orchestra, as pasted from a mail or a manual for example. The CSD can also be generated directly from the clipboard contents.

The package makes it easy to toggle from an orc/sco pair to a CSD. Compilation of both formats can be driven from Emacs.

Documents can be processed on-the-fly with multiple configurations of Csound which can be customized and made available from a menu. It is thus very easy to swap from DAC rendering to WAV file compilation, or from different versions of Csound.


Extending Csound documents

Csound-x makes it possible to have richer Csound documents by adding either comments or mark-ups making sense for Emacs.

The documents are still valid for direct compilation by Csound; simply they also embed high-level information making them easier to work on. For example, a CSD can become tunable from an Emacs menu, or become an algorithmic template for a whole family of CSD documents.

A library for score generation is included (see The i library.) so that the score section of a CSD can be algorithmically generated or modified.

MIDI data can be included in various form, most notably using Keykit format (see Handling MIDI data.), (see The k library.)

Support for algorithmic generation of instruments is being implemented (see Csound Elisp.)


Generating Csound documents

Csound-x can also work upside-down: instead of editing Csound documents within Emacs it is possible to directly compose in Emacs Lisp with the underlying temporary CSD document remaining implicit. (see Csound Elisp.)


Providing Csound access to a larger system

Csound-x is a main component of Surmulot, an open system for musical composition (see (Surmulot)Top.)

Surmulot home page: http://www.zogotounga.net/surmulot/surmulot.html



Next: , Previous: Overview, Up: Overview

Features provided by Csound-x


Previous: Features, Up: Overview

Csound-x extensions to the CSD format

Csound-x defines the following markups to be used outside the <CsSynthesizer>...</CsSynthesizer> section of a CSD document:

<ELISP>...</ELISP>
See Embedded elisp.
<SES>...</SES>
See Matrices & spreadsheets.
<KeyPhrase>...</KeyPhrase>
See Handling MIDI data.
<MPhrase>...</MPhrase>
See Handling MIDI data.

Csound-x also gives a specific meaning to comments in orchestras and scores that start with ;|


Next: , Previous: Overview, Up: Top

How to get Csound-x and its external components

Csound-x is released under the General Public Licence, version 2.

The latest version is available as a stef-elisp.zip archive from http://www.zogotounga.net/comp/csoundx.html

Surmulot provides Csound-x and much more, with no installation hassle: http://www.zogotounga.net/surmulot/surmulot.html


The following programs are either required by Csound-x, or at least considered very useful:


Next: , Previous: Distribution, Up: Top

1 How to install Csound-x


The fast way

Download Surmulot to have a fully working Csound-x with many extra features (notably graphical interfaces) by simply unzipping an archive: http://www.zogotounga.net/surmulot/surmulot.html

The following only applies if you want to install Csound-x by yourself.


Preparation

First of all, install the required packages See required utilities.

On Emacs 22 you can skip this step, although you will miss MMM.


Installation

Unpack the stef-elisp.zip archive in your site-lisp directory, then add the following line to your .emacs file:

     (require 'stef-elisp)

Evaluate it to have the package immediately available.


Compilation

You may byte-compile every file in the distribution for faster execution.


Configuration & customization

A few variables need to be set in order to fit your system via

     M-x customize-group csound-x

Most variables can keep their default setting. If you don't understand what they do, just leave them as is.

On windows system, your Csound installation should be detected automatically at start-up. You can test this for example by evaluating the code in See Csound Elisp.


Next: , Previous: Installation, Up: Top

2 Basic usage


Editing orc&sco

Csound-x provides the major modes csound-sco-mode and csound-orc-mode for editing respectively score and orchestras. These are modified versions of the modes written by John Fitch.

See Score editing. See Orchestra editing.


Editing a CSD

Csound-x also provides a major mode for CSD buffers. It is recommended to use the CSD format when starting a project from scratch. See CSD editing.


Editing orc&sco within a CSD

When the MMM mode is installed (See Distribution.), it is possible to have the score and orchestra major modes enabled together in a single CSD buffer.

Alternatively, the score and orchestra sections of a CSD can be edited independently via indirects buffers. This should happen by default when the MMM mode is not available (in Emacs an indirect buffer is just another interface to the original buffer; so editing the score or orchestra there actually edit the CSD. See (emacs) Indirect Buffers.)


From orc & sco to CSD

Both csound-sco-mode and csound-orc-mode menus provide a "Wrap in .CSD" item. The simplest way to use it is to divide the Emacs frame in two windows, with a score buffer in one and an orc buffer in the other. Invoking "Wrap in .CSD" from any of the buffers will create a new CSD buffer with the same name as the buffer you called it from, embedding the codes for orchestra and scores. If no associated buffer exist, a buffer with the same root name will be detected; if no such buffer exists, you will be asked if you want to go and fetch a file, or if the corresponding CSD section should be left empty.

The CSD buffer name is built from the original sco or orc buffer. Note that if a buffer with that name already exists and you accept to overwrite it, only the <Score> and <Orchestra> sections will actually be overwritten. This makes it possible to split a CSD buffer into an orc/sco pair, work on them, then assemble them back in the CSD, without loosing any extra information (such as the <Options> section) in the initial CSD.

When a CSD is first created, by default the "<Options>" section is left void. Customize the variable cscsd-default-options to define the content you want there.

"Wrap in .CSD" either updates an existing CSD buffer or creates one. The initial sco and/or orc buffers are never modified nor killed. The associated command is:

— Command: cscsd-wrap-buffer

Associate the current buffer to a sco or orc file and create a csd; if `next-window' displays a complementary buffer, it is proposed as default otherwise we look for a complementary buffer with the same root name or else we look for a complementary file in the same directory ... and if all of this fails we just ask.

do nothing if we already are in a csd buffer


From CSD to orc & sco

In the “CSD” menu, item "orc/sco -> Split in orc/sco" creates a score and an orchestra buffers from the current CSD buffer. The name of the initial buffer is kept; for example "yop.csd" leads to "yop.sco" and "yop.orc". The initial CSD is left untouched.


CSD from scratch

Still in the “CSD” menu, item "Build a true CSD" tries to analyse the buffer content which should contain one score and one orchestra, and attempts to wrap this into a true .csd format. The intent of this command is for example to easily convert a text from an email into a CSD. It tries to guess where starts orc and where starts sco by looking for lines matching the regexps listed in 'cscsd-orc-delimiter-regexps and 'cscsd-sco-delimiter-regexps. The associated command is:

— Command: cscsd-auto-import

Create a csd from the full contents of current buffer

— Variable: cscsd-orc-delimiter-regexps

List of regexps to be tried in order to guess where the orchestra starts in a plain text file known to contain a score and an orchestra with no csd syntax to wrap them.

— Variable: cscsd-sco-delimiter-regexps

List of regexps to be tried in order to guess where the score starts in a plain text file known to contain a score and an orchestra with no csd syntax to wrap them.

"Build a CSD from clipboard" is similar, only it creates a CSD from the content of the OS clipboard. Associated command is

— Command: cscsd-import-from-clipboard

Create a csd from the contents of the OS clipboard

To extract a CSD from a buffer (for example an info page), use
— Command: cscsd-at-point

Create a csd from the contents of current buffer around point


Next: , Previous: Basic usage, Up: Top

3 Score editing

The csound-score provides indentation, fontification and a “SCO” menu.


edit a f-table


Next: , Previous: Score editing, Up: Top

4 Orchestra editing

... this is not fully documented yet


Indentation and completion

Use `<tab>' to indent the line at point.

If the line only contains an opcode fragment, then successive `<tab>' strokes propose in turn all possible completions, that is all opcodes containing the fragment as a substring, along with all templates and some documentation; press `y' to accept a template, or `<esc>' to cancel the whole operation.

Alternatively, you can get another kind of completion with `M-<space>': this inserts in turn a one-line template, without documentation, for each opcode beginning with the fragment.


Next: , Previous: Orchestra editing, Up: Top

5 CSD editing

csound-csd-mode is a major mode for CSD files, which gets started whenever you visit a file with extension .csd.



Next: , Previous: CSD editing, Up: CSD editing

5.1 The CSD menu

The “CSD” menu is shared among all types of csound buffers.

With fewer items in simple orchestra and score buffers, it allows conversion to CSD and access to high-level editing features.

In CSD buffers the “CSD” menu appears in full; it can be divided in the following sections:


High-level tuning

This part of the menu is dynamically computed to reflect the meta-controls defined in the CSD. See CSD meta-controls.

These include snapshots and Embedded Emacs Lisp (EEL) settings. EEL provides a clean way to integrate Emacs Lisp code within a CSD document, so that it can become tunable at a very high level, become the template for a whole family of algorithmic compositions, or even become a program in itself. It is a very powerful feature that can bring you very far away from usual csound programming... See Embedded elisp.


Structure navigation and editing

The "Structure" submenu allows both exploration of the CSD structure and individual edition of its different components.

Exploration can be driven via the speedbar which allows you to directly jump to critical places in the document: score, orchestra, intruments, f-tables, score matrices, SES areas, EEL meta-comments.

Score and orchestra can be separated either virtually, via indirect buffer, or really, by creating new independent score and orchestra buffers.

The submenu also provides ways to rebuild the CSD, or create one from the clipboard contents.


Documentation and orchestras library

This section gives access to Csound HTML documentation. See Integrated documentation.

It also provides entry points to the orchestras library. See Libraries and repositories.


High-level editing

... this is not fully documented yet


Processing

The last items invoke external softwares (most notably Csound) for processing the .csd file. See Interactive invocation from CSD.


Previous: The CSD menu, Up: CSD editing

5.2 Useful public functions for CSD handling

... this is not documented yet


Next: , Previous: CSD editing, Up: Top

6 Libraries and repositories


The orchestras library

The “orc/csd” sub-menu gives access to a user-defined library of orchestra code. You may search for a string or a regular expression within the whole library.

To define the directories constituting the library, use items “Set path” and “Set recursive path” (all directories in the recursive path add their subdirectories tree to the library). Within these directories, all *.orc, *.csd and *.udo files are part of the library.

The result of a query appears as a list of files in a buffer from where you can either jump to a given source (by clicking the file name) or directly process the file (using the left button, which may not exists if no score was found).


The code repository

“Code repository” is a sub-menu common to all csound modes menus. It provides insertion of code chunks stored in *.csr files, a simple format used by CsEdit (Csound code editor for Windows) for its "code repository" feature. So these files can be shared between CsEdit and Emacs.

CsEdit home page is http://flavio.tordini.org/csound-editor

You need to customize the variables 'cscsd-csr-files (this one should be a list of the *.csr file to import within Emacs) and 'cscsd-current-csr-file (this one defines which file is getting edited when registering a new bit of code).

Once this is done, the region can be added to the repository with the menu item "Register region", while you can directly edit (and thus correct or improve) the corresponding .csr file with the item "Edit csr file"

By default, you should have some example code stored in the file somecode.csr (provided that csound-x is a folder in your ~/site-lisp, which is the recommended installation. see Installation)

Note: you may also want to customize 'cscsd-csr-author in order to provide a value for the "Author" fields in the *.csr


Next: , Previous: Libraries and repositories, Up: Top

7 Csound invocation

Csound can be operated as an Emacs sub-process provided that the following customizable variables are correctly set:

— Variable: cscsd-csound-binary

The default csound binary

— Variable: cscsd-process-file

A list of pairs (NAME FUNCTION) or (NAME SYSTEM-CALL) among which you can choose which process is to be invoked by the "process file" and "process regions" items from the "Csd" menu.


Next: , Previous: Csound invocation, Up: Csound invocation

7.1 Interactive invocation from CSD

“CSD” menu items for processing


Access to rendered audio file

When the current processing compiles an audio file, its location is stored in the buffer-local variable 'cscsd-latest-audio-file. When this variable is non-nil, “Play file” and “Edit file” items are activated.

"Play file" does whatever the customizable shell command 'cscsd-shell-play-audio does. "Edit file" action is similarly defined by customizable shell command `cscsd-shell-edit-audio.


— Variable: cscsd-latest-audio-file

Record the name of the latest compiled audio file. It is buffer-local: an audio file can thus be associated to each CSD or score buffer.

— Variable: cscsd-shell-play-audio

Shell command used to play an audio file. It should feature a single %s occurrence, to be replaced with the audio file name.

— Variable: cscsd-shell-edit-audio

Shell command used to edit an audio file. It should feature a single %s occurrence, to be replaced with the audio file name.


Next: , Previous: Interactive invocation from CSD, Up: Csound invocation

7.2 Interactive invocation from orc & sco

... this is not documented yet


Previous: Interactive invocation from orc&sco, Up: Csound invocation

7.3 Invocation functions

Commands

— Command: cscsd-process

Process the file visited by the current csd buffer. What this means exactly depends on the function or command associated to `cscsd-current-processing' in `cscsd-process-file'. If needed, the audio file name is built from the current buffer file name or fetched from the <CsOptions> area.

— Command: cscsd-process-region

Process the region as a full csd, with `cscsd-process'


Low-level functions

— Function: cscsd-call-csound syscall csd-file &optional audio-file midi-file omacros smacros

Compile CSD-FILE into AUDIO-FILE, with midi input from MIDI-FILE. SYSCALL is interpreted as a shell command by function `cscsd-interpret-command'.

— Function: cscsd-interpret-command syscall csd-file &optional audio-file midi-file omacros smacros

Interpret SYSCALL as a shell command to be used in order to compile CSD-FILE into AUDIO-FILE, using midi input from MIDI-FILE.

SYSCALL must be a string containing up to three occurences of %s, for example: "$csound -dHWo %s %s"

if there is only one %s, it will stand for CSD-FILE.

if there are two of them, the first occurence of %s will be replaced by AUDIO-FILE, and the second %s by CSD-FILE, except if the string "DAC" is detected among the options, in which case the first %s is replaced with CSD-FILE and the second one with MIDI-FILE

if three occurences of %s appear, they stand for AUDIO-FILE, CSD-FILE and MIDI-FILE, respectively.

OMACROS is a list of cons cells of form '(("MacroName" . MacroValue) ..) defining orchestra macros, which are appended to SYSCALL as –omacro: options. SMACROS is a similar list defining –smacros: options, for score.

when AUDIO-FILE is nil (and required), it is built from CSD-FILE with an extension depending on the detected flags in the SYSCALL: .wav if a -W is detected, .aif if a -A, no extension otherwise. if no option flag is provided the <CsOptions> area is analysed and the filename can be detected there.

when MIDI-FILE is nil (and required), the user is interactively prompted for a file name.

SYSCALL may include the substring "$csound" which is then replaced by the returned value of function `cscsd-csound-binary'.

this function has the side effect of setting buffer-local variables `cscsd-latest-audio-file' and `cscsd-latest-midi-file', respectively to AUDIO-FILE and to the appropriate MIDI file, if any.


Next: , Previous: Csound invocation, Up: Top

8 Integrated documentation


csound-doc provides straightforward access to Csound documentation: several brands of HTML manuals, Winhelp file, CsoundAV manual

Getting the docs

the "canonical" HTML manual comes with Csound 5

the older "official" HTML manual (David Boothe's) homepage is http://www.lakewoodsound.com/csound/hypertext/manual.htm

the older "alternative" HTML manual (Kevin Conder's) homepage is http://www.kevindumpscore.com/download.html

the older Rasmus Ekman's Winhelp file can be possibly be found somewhere on the web...


Customization

go to the 'csound-doc customization group and define your settings as follow:

choose one of the HTML manual with 'csdoc-which-manual. this will be the manual used to document opcodes and insert opcode templates

set 'csdoc-html-directory and 'csdoc-html-entry-point as needed to fit your installation:

'csdoc-html-directory must be the directory where lives the manual you just choosed

'csdoc-html-entry-point can be any HTML page: it is only used by the “Browse HTML documentation” menu item. So it is possible to have another HTML manual at hand through this variable.

if you want to use the emacs w3 browser instead of the default external one, toggle 'csdoc-use-w3' on (note that w3 is an independant emacs package; it is not installed in the default configuration). in that case if can have the doc window pop up in a specific frame by adding the following to your .emacs:

     (add-to-list 'special-display-buffer-names "*Csound Documentation*")

set 'csdoc-winhelp-file to the location of csound.help

if this is not correct, Winhelp support will simply be dropped altogether.

you may also provide access to CsoundAV HTML docs by setting 'csdoc-csoundAV-manual-directory


Usage

when working with csound-orc-mode, a couple of items should now appear in the “ORC” menu

Here are some of the corresponding interactive commands:

M-x csdoc-html-document-opcode
document the opcode at point, by opening the corresponding HTML page in the associated browser
M-x csdoc-insert-opcode-html-template
insert a template for the opcode at point (or provided in the minibuffer).
M-x csdoc-browse-html
browse the HTML documentation


Next: , Previous: Integrated documentation, Up: Top

9 Score matrices

csound-mx allows the definition of matrices (“selections”) within a score, and provides ways to work on them; it also adds an extensible Matrix menu to the buffers in csound-sco mode, giving an easy access to the most useful functions of this package.

Basic usage

Advanced usage


Next: , Previous: Score matrices, Up: Score matrices

9.1 Defining selections

A "selection" is a rectangular part of a score identified by two comments. Example:

     i 1 24.78 -0.94 2793.230.7 0.4 ;_meuh_b.5
     i 1 16.06 -0.96 3413.510.6 0.3
     i 1 29.98 -0.68 2792.310.6 0.7 ;_meuh_e.6
     i 1 28.27 -0.443636.460.5 0.5

Here a selection called "meuh" (the selection id) begins at the 5th column in the first line and ends at the 6th column in the third line. It represents the matrix

     0.7 0.4
     0.6 0.3
     0.6 0.7

You can define as many selections as you want by writing the corresponding comments. However, the two Matrix menu items "Select rectangular region" and "Select column" make it easy to do it with a few mouse clicks.

"Select rectangular region" makes a selection from the rectangular region between point and mark (if any), "Select column" scans the column at point upward and downward and selects a one-column matrix. The scan is stopped by any line which is not a i-statement, be it a comment or an empty line.

Both queries for a selection id (any keyword composed with letters and digits). You may just press <RETURN>, in which case the id will be "" and the selection will be the current one. The previous current selection, if any, will be lost.

The current selection is important since it is the one that can be directly accessed through the other menu commands. "Store current selection" queries for an id and give it to the current selection (which is not current any more, then), "Make a selection current" queries for an existing id and creates a new current selection from the corresponding one (this does not remove it) and "Remove a selection" queries for an id and erase the corresponding selection (this does not change the current one, except if it is the removed one)

If scomx-highlight-matrices is t, all selections are displayed with a background color: by default the color is scomx- selection-color for non-current selections, and it is scomx-main-selection-color for the current selection.

But, if a selection id is recognized as a color name by Emacs, the selection will be displayed in that color. So the simplest way to have an informative display is to call your selections "green", "orange", "gold", "blue", etc.

Alternatively, you may also customize scomx-colors-alist which defines a list of ids with associated background colors (note that the so-called "background colors" can actually be property lists defining a face better that the background color only; see the default alist for examples).


Next: , Previous: Defining selections, Up: Score matrices

9.2 Operating on the current selection

The "Sort" menu item queries for a column number and sort the current selection according to that column.

"Apply script on matrix" let you invoke an external script or utility (such as a shell command): just provide its name at the prompt. The script is given from stdin a temporary text file containing the current selection. It should output to stdout a selection of the same size, in the same format (plain text), which will replace the current selection.

"Operate on matrix" and "Operate on parameters" allow any mathematical operation to be performed on the current selection. They indirectly invoke the Calc package to perform the calculations (see (Calc)Top). This is a wide topic, because Calc is very powerful and also not so easy to work with . However, simple operations are performed simply... see the advanced usage chapter for more in-depth considerations (see Basic functions). We will proceed here with basic stuff.

"Operate on matrix" queries for a mathematical operation affecting variable m, which is the matrix represented by the current selection.

"Operate on parameters" queries for a mathematical operation affecting variable p, which takes in turn the value for each field in the matrix m. Besides, you can use variables nc and nr to represent the position of p in the matrix.

The expressions you input will be interpreted as Calc data (see (Calc)Programming). Two formats are available: algebraic and lisp.

By default, you are first queried for an algebraic expression. If you just press <RETURN>, you will be prompted for a lisp expression. This behaviour can be inversed by setting scomx-propose-algebraic-input-first to nil (do so via the customization system)


An example algebraic expression is
     10+m

This offsets all values in the matrix by 10. The corresponding lisp form is:

     (+ 10 m)

The tricky part with the lisp format is that what you input will be evaluated within a defmath macro. Please read the "programming" chapter of Calc info for what this means exactly (see (Calc)Defining Functions). The most important point is that floats must appear in a specific format. For example, it is an error to write

     (+ 10.05 m)

Instead, you must write

     (+ :"10.05" m)

In general, it is thus simpler to use the algebraic format. But lisp is much more powerful, so eventually it all depends on what you want to do.


Next: , Previous: Operating on the current selection, Up: Score matrices

9.3 Examples


"Operate on matrix" examples (algebraic format):
multiplying m by 2:
2m
replacing all values with their opposite:
neg(m)
keeping only 5 significant digits:
clean(m,5)

"Operate on matrix" examples (lisp format):
direct column matrix filling:
'(vec (vec 10 20 30))
Cmask invocation (random numbers):
(cmask m "range 0 5") See Cmask integration.
swapping columns 1 and 2:
(swap-rows m 1 2)

..note that in the last example it's "rows": this is because internaly the matrix is transposed


"Operate on parameters" examples (algebraic format):
replacing values with their sine:
sin(p)
filling with a function of the indexes (1):
0.1*nr
filling with a function of the indexes (2):
nr+100nc
filling with a function of the indexes (3):
clean(exp(0.1*nr),4)


Next: , Previous: Examples, Up: Score matrices

9.4 Symbolic operations

Expressions within brackets such as [($CNT./3)+10] are understood and symbolically processed. For example, applying p^2 on such a parameter would result in [(($CNT./3)+10)^2]

The @ and @@ operators are supported. Note that the result of an operation is kept in symbolic form only if it can not be simplified. As an example, applying p or m (that is, the identical operation) on the matrix

     [1+1]     [1+$x.]
     [3^$CNT.] [3^(2+2)]
     [@513]    [@@513]
     [@$n.]    0.15

...results in:

     2         [1+$x.]
     [3^$CNT.] 81
     1024      513
     [@$n.]    0.15

... while applying p^2 would result in:

     4             [(1+$x.)^2]
     [3^(2*$CNT.)] 6561
     1048576       263169
     [@$n.^2]      0.0225


Next: , Previous: Symbolic operations, Up: Score matrices

9.5 Basic functions

For complex manipulations, you will need to do some programming. Here are documented the most useful functions and macros defined by the csound-mx.el package.

Note: all functions having id (a selection name) as an argument must be called from within the score buffer.


Wrappers for the Calc world

— Macro: with-defmath &rest body

Evaluates body within a defmath macro and returns a number

Evaluating within a defmath means that all Calc extensions are available, and that Calc format must be used (please refer to the Calc manual for details) See (Calc)Top.

          (/ 5 3)
               => 1
          (with-defmath (/ 5 3))
               => 1.6666667
     

— Macro: with-alg-defmath &rest body

Evaluates body within a defmath macro and returns the result as a string (in algebraic syntax)

          (with-alg-defmath (/ 5 3))
               => "1.6666667"
     

— Macro: with-raw-defmath &rest body

Evaluates body within a defmath macro and returns a Calc data structure in raw form

          (with-raw-defmath (/ 5 3))
               => (float (bigpos 667 666 16) -7)
     

— Macro: with-defmath-import vlist &rest body

Similar to 'with-defmath, but allows in VLIST the importation of symbols which will refer to the same value inside the defmath as outside (sort of "globals").

          (let ((A 5)(B 3))
            (with-defmath-import (A B) (/ A B)))
               => 1.6666667
     

Grabbing and yanking matrices (with Calc)

— Function: scomx-grab-matrix id

Reads the score selection id and returns a matrix in raw Calc format

Note: this function can not be used inside a defmath.

          i 1 24.78 -0.94 2793.230.7 0.4 ;_meuh_b.5
          i 1 16.06 -0.96 3413.510.6 0.3
          i 1 29.98 -0.68 2792.310.6 0.7 ;_meuh_e.6
          
          (scomx-grab-matrix "meuh")
               => (vec
                   (vec
                    (float 7 -1)
                    (float 6 -1)
                    (float 6 -1))
                   (vec
                    (float 4 -1)
                    (float 3 -1)
                    (float 7 -1)))
     

In the process, all macros are replaced by variables whose names start with macro

          i 1 24.78 -0.94 2793.23[$X.] 0.4 ;_meuh_b.5
          i 1 16.06 -0.96 3413.51[$X.+0.1] 0.3
          i 1 29.98 -0.68 2792.31[$X.+0.2] 0.7 ;_meuh_e.6
          
          (scomx-grab-matrix "meuh")
               => (vec
                    (vec
                     (var macroX var-macroX)
                      (+
                       (var macroX var-macroX)
                       (float 1 -1))
                      (+
                       (var macroX var-macroX)
                       (float 2 -1)))
                    (vec
                     (float 4 -1)
                     (float 3 -1)
                     (float 7 -1)))
     

— Function: scomx-yank-matrix matrix id

Write matrix in the score selection id

          (scomx-yank-matrix '(vec (vec 1 2 3) (vec 4 5 6)) "meuh")
               =>
          
          i 1 24.78 -0.94 2793.231 4 ;_meuh_b.5
          i 1 16.06 -0.96 3413.512 5
          i 1 29.98 -0.68 2792.313 6 ;_meuh_e.6
     

— Function: scomx-shell-command-with-matrix script id

Invoke the shell command: script < input-file > output-file where input-file is a temporary file containing selection id as plain text, and output-file a temporary file where a replacement for id is read


— Macro: scomx-operate-m id body

Evaluates body within a defmath macro, interpreting the variable m as the matrix defined by selection id, and replaces that selection with the result of the evaluation (which must be a matrix of same dimensions)

          (scomx-operate-m "meuh" (neg m))
               => replace all values in selection "meuh" with their opposites
     

— Macro: scomx-operate-p-nc-nr id body

Evaluates body within a defmath macro for each element of the matrix defined by selection id, replacing that element with the result of the evaluation. The variable p is interpreted as the element initial value, nr as its vertical position (starting with 1 at the top) and nc as its horizontal position in the matrix.

          (scomx-operate-p-nc-nr "meuh" (+ p (* 0.1 nr)))
               => offset all values in selection "meuh"
                  by an amount depending on their vertical index
     

Grabbing and yanking matrices (directly)

— Function: scomx-elt col row &optional sid set-to

Fetch the element, a string or nil, at column COL and row ROW in matrix SID if SID is not provided, it defaults to "", the current selection. (note that columns and rows indexes start at 1)

If SET-TO is non nil, it replaces the previous matrix element. (SET-TO may be a string or a number)

This function does not perform any interpretation of the returned data. It is either nil if there is no element in the matrix at these coordinates, or the string at point matching the regexp “[^ \t\n\r]+”

          i 1 24.78 -0.94 2793.230.7 0.4 ;_meuh_b.5
          i1 16.06 -0.96 3413.510.6 0.3
          i 1 29.98 -0.68 2792.310.6 0.7 ;_meuh_e.6
          
          (scomx-elt 1 1 "meuh")
               => "1"
          
          (scomx-elt 1 2 "meuh")
               => "i1"
     


Next: , Previous: Basic functions, Up: Score matrices

9.6 Cmask integration

Cmask is a powerful stochastic event generator, intended to generate full Csound scores. However, its is also very useful for simply filling a single matrix in a score. This is how csound-x uses it.

First of all, you must be somewhat familiar with Cmask concepts. Please read its very good documentation before you proceed with the rest of this chapter.

Cmask is not integrated by default. You need to turn 'scomx-Cmask-support on and to set the values of 'scomx-Cmask-binary and 'scomx-Cmask-tmp-file (do so via the customization system)

Now here is how it works:

— Function: cmask matrix l1 &optional l2 l3 l4 l5

Invoke Cmask for generating a p3 field which will be stored in the last column of matrix. Returns the modified matrix. If there is more than one column in matrix, the first one is considered as the p2 values of reference when generating the p3 field. Weither it is actually a p2 column does not matter, but it must be sorted.

If there is only one column, the p2 values are assumed to range evenly from 0 to 1.

cmask is intended to be used within a 'scomx-operate-m body (as it is defined by a 'defmath macro)

example:

     (scomx-operate-m "meuh" (cmask m "seg [0 1]" "quant 0.1 1"))
          =>
     
     i 1 24.78 -0.94 2793.231 0 ;_meuh_b.5
     i 1 16.06 -0.96 3413.512 0.5
     i 1 29.98 -0.68 2792.313 1 ;_meuh_e.6

Here the cmask function had Cmask process the following code:

     f 1 4
     p1 const 1
     p2 item cycle (1 1)
     p3 seg [0 1]
     quant 0.1 1

The first three lines are automatically calculated so that the p2 values mimic the first column of the targeted matrix, which must be sorted (otherwise cmask will refuse to proceed). If there is only one column, then the p2 values are supposed to range evenly from 0 to 1 within the scope of the matrix.

This is important since the p2 values are the reference for all time-dependent Cmask parameters.

In our example, there is no time dependency: seg [0 1] means that the generated values must go from 0 to 1. But consider osc sin 1 . This generate a sine with frequency 1, thus the p2 values matter: with the matrix "meuh", three periods would be spawned (because the first column is [1 2 3]), while with a single column matrix it would be only one period (since p2 is supposed to go from 0 to 1).

This may not be very clear, so I invite you to just try it and get the feeling. See also the "Cmask" submenu in the Matrix menu for an easier access to the full power of Cmask.


The following are example arguments for "Operate on matrix":

uniform randomvalues:
(cmask m "range 10 15")
uniform random values (with precision 4):
(cmask m "range 10 15" "prec 4")
values from 0 to 1:
(cmask m "seg [0 1]")
values from 0 to 1 (quantified):
(cmask m "seg [0 1]" "quant 0.05 1")
a more complex distribution:
(cmask m "gauss [0.1 0.2] [0.3 0.8]" "mask 1000 2000" "quant 0.05 1")


Next: , Previous: Cmask integration, Up: Score matrices

9.7 The repository

At the bottom of the "Matrix" menu is a code repository. It makes it faster to perform complex calculations on matrices, but it is worth noting that everything featured there can be done (albeit quite tediously) through the menu items "Operate on matrix" and "Operate on parameters".

The repository is built from the evaluation of the customizable list of function 'scomx-Matrix-menu-definitions. By default it only contains the symbol 'scomx-Matrix-menu, which is the name of the function defining the code provided by default. If you look at it, you will be able to write your own equivalent functions: adding their names to 'scomx-Matrix- menu-definitions will make your code available from the repository.

Whenever you change something in this code, invoke the "Update" item in order to refresh the menu.

Among the proposed submenus, one is called "Cmask" and gets enabled if 'scomx-Cmask-supportis non-nil. From there you can access most of Cmask features and apply them to the current matrix. Beware that only the last column is affected, and that the first column, if it is a different one, provide the p2 values for Cmask. See cmask.


Previous: The repository, Up: Score matrices

9.8 Matrices & spreadsheets

If you installed the SES package, you should have the following four items in your Matrix menu (see Score matrices):

They allow for each defined selection (that is, a matrix) to be associated to a spreadsheet buffer. The spreadsheet is completely independent from the source sco or CSD file, but its content can be stuffed back in the source whenever you want, either directly or as a <SES>...</SES> markup in a CSD file, in which case the formulas can be kept accross sessions.

The usage is pretty simple. Here is an example: suppose we have a CSD buffer with the following score section:

     <CsScore>
     
     i 1 0 3
     i 2 4 3
     i 3 8 3
     i 4 12 3
     i 5 16 5
     e
     </CsScore>

... where we define a gold matrix as follows:

     <CsScore>
     
     i 1 0 3 ;_gold_b.1
     i 2 4 3
     i 3 8 3
     i 4 12 3
     i 5 16 5 ;_gold_e.2
     e
     </CsScore>

Now doing "Selection to spreadsheet" with argument "gold" creates a SES buffer with 2 columns for the source selection, plus a number of extra columns defined by scomx-spreadsheets-borders (by default itīs 3):

      A       B       C       D       E
      ---------------------------------------
           1       0
           2       4
           3       8
           4      12
           5      16

Depending on the value for scomx-framed-spreadsheets, the SES buffer may appear in the other window or in a specific frame.

Now we set the formula for B1 as (* 2 A1) and copy this to all cells in the B column (see the SES documentation for details, see (SES)Top.):

      A       B       C       D       E
      ---------------------------------------
           1       2
           2       4
           3       6
           4       8
           5      10

At this point, if we go back to the CSD buffer and do a "Spreadsheet to selection" with argument "gold", the gold matrix will be updated according to the content of the spreadsheet:

     <CsScore>
     
     i 12 3 ;_gold_b.1
     i 24 3
     i 36 3
     i 48 3
     i 510 5 ;_gold_e.2
     e
     </CsScore>

This did not save the formulas we used to calculate the second column. If we want to keep them, we do "Spreadsheet to XML", again with a "gold" argument. A <SES>...</SES> markup area is then inserted at the end of the CSD buffer. Later on, invoking "XML to spreadsheet" with "gold" will re-create the SES buffer complete with its formulas, making it possible to work again on the gold selection.

The parameter 'cscsd-ses-areas-invisible defines weither the content of a SES XML area is actually displayed in the CSD buffer. By defaults it is not.

Note that "Spreadsheet to XML" does not imply a "Speadsheet to selection". It does not change the score content: this is only a way to store the spreadsheet associated to a matrix for a later usage. If the matrix size or content is changed meanwhile, or if the selection disappear altogether, this will not be reflected in the XML area.

The extra columns (and rows) in the SES buffer may be used to store any temporary or seeding value. When the matrix is yanked back, they are ignored; when the spreadsheet is stored as an XML area, they are stored as any other component of the spreadsheet (see the SES documentation for details about its file format).

For example, we can set B1 formula to (* D1 A1) and copy this in the B column:

      A       B       C       D       E
      ---------------------------------------
           1       2    fact:      2
           2       4
           3       6
           4       8
           5      10

now if we change the D1 value to 3, the matrix becomes:

      A       B       C       D       E
      ---------------------------------------
           1       3    fact:      3
           2       6
           3       9
           4      12
           5      15

we can check that when stuffing back the values, only the two first columns are taken into account:

     <CsScore>
     
     i 13 3 ;_gold_b.1
     i 26 3
     i 39 3
     i 412 3
     i 515 5 ;_gold_e.2
     e
     </CsScore>



Note that Calc is integrated to the spreadsheet through the macros 'calc-cell and 'calc-alg-cell, so you may type this kind of forms to edit a cell contents:
     RET (calc-cell (round (/ A1 B1)))
     RET (calc-alg-cell "round(A1/B1)")

The parameters 'scomx-ses-calc-shortcut (default is 'm:) and 'scomx-ses-calc-alg-shortcut (default is 's:) provide shortcuts:

     RET (m: (round (/ A1 B1)))
     RET (s: "round(A1/B1)")


Next: , Previous: Score matrices, Up: Top

10 Handling MIDI data within a CSD

Csound-x can interface with several systems for musical composition; one of them is Keykit from which it borrows the MIDI data representation (see The k library).

Keykit home page: http://thompsonresidence.com/keykit

Another system is muO, based on Squeak (see (Surmulot)Top). Surmulot home page: http://www.zogotounga.net/surmulot/surmulot.html


Using Keykit as MIDI engine

If you have Keykit installed on your system, customize the group 'keykit so that csound-x knows how to work with it.

It is then possible to generate a MIDI file from within a CSD document. This happens in specific areas of the form:

     <KeyPhrase label="name">
     ...
     </KeyPhrase>

where ... stands for arbitrary Keykit code. This code is expected to define a KeyPhrase variable (whose value will become the MIDI file)

The “KeyPhrases” entry under the “CSD” menu lists all names for the currently existing <KeyPhrase> areas in the buffer. From the corresponding submenu it is possible to have the phrase as MIDI input.

The processing works as follows:


Using muO as MIDI engine

In very much the same way we can generate MIDI data from Squeak by defining specific areas of format

     <MPhrase label="name">
     ...
     </MPhrase>

where ... stands for Smalltalk code defining a mphrase variable.

Surmulot widgets can do this automatically: see (Surmulot)Musical phrase editor and see (Surmulot)MIDI.



Example

Here is a full CSD example (the orc code is from Istvan Varga, simplified and adapted for MIDI by me):

     <KeyPhrase label="loop">
     KeyPhrase=repeat('ad50,e,d',10)
     </KeyPhrase>
     
     <KeyPhrase label="fractal">
     KeyPhrase=fractal('ad200,e,d,g,a')
     </KeyPhrase>
     
     <MPhrase label="fractal">
     |mphrase| mphrase:='ad200,e,d,g,a' kmusic fractal.
     </MPhrase>
     
     <CsoundSynthesizer>
     <CsInstruments>
     /* bsln1.orc - written by Istvan Varga */
     sr      =  44100
     kr      =  22050
     ksmps   =  2
     nchnls  =  1
     
     massign 1, 1
     
             instr 1
     
       imp4  notnum                                  ; pour MIDI
       imp5  veloc                                   ; id
       imp6  midictrl        10, 80, 92
     
       icps  =       440*exp(log(2)*(imp4-69)/12)    ; oscillator frequency
       iamp  =       0.0039+imp5*imp5/16192          ; amplitude
       ifrq1 =       440*exp(log(2)*(imp6-69)/12)    ; filter start freq.
     
       kamp  linsegr 1, 0.5, 1, 0.025, 0             ; release envelope
     
       kcps  port    icps, 0.005, icps*0.5           ; osc. frequency
       knumh =       sr/(2*kcps)
     
       kffrq port    0, 60/150, ifrq1                ; filter frequency
     
       a1    phasor  kcps                            ; oscillator
       a1    =       1-2*a1
     
       a1x   butterbp        a1, kffrq, icps*1.0     ; filters
       a1x   =       a1x*(2+kffrq/kcps)              ; correct amplitude
       a1    =       a1x+a1*0.5
       a1    butterlp        a1, kffrq
     
       a1    =       taninv(a1* 2.5*iamp) ; distortion
       a1    =       a1*kamp*20000
     
             out a1
             endin
     
     </CsInstruments>
     
     <CsScore> </CsScore>
     </CsoundSynthesizer>

Get this code in a CSD buffer by clicking anywhere inside it and doing `M-x cscsd-at-point'.

Now in the new CSD buffer the menu items "CSD->KeyPhrases->loop" and "CSD->KeyPhrases->fractal" will have Keykit process the corresponding MIDI phrases, as defined in the <KeyPhrase> areas.

Similarly, "CSD->MPhrases->fractal" will let you process or edit via ĩO the "fractal" phrase.


Next: , Previous: Handling MIDI data, Up: Top

11 Embedded Emacs Lisp

If you got Csound-x through the stef-elisp distribution, you should also find there embedded-elisp-library.el which provides the embedded-elisp minor mode.

Basically, doing "embedded elisp" means stuffing a document (in our case a CSD document) with lisp code areas intended to be evaluated interactively in order to modify or process the document.

To activate csound-csd-mode support for embedded elisp, select the “CSD -> Invoke EEL mode” menu item.

This gives birth to a “EEL” menu from which you can manage <ELISP> areas. Please refer to the documentation in embedded-elisp-library.el for general info about the minor mode.

When the customizable variable cscsd-use-EEL is non-nil, EEL mode is invoked automatically when an <ELISP> area is detected in the CSD document.


The next sections introduce a set of libraries intended to be used with embedded elisp:

A simple example.

Here is a CSD document with an <ELISP> area allowing the exploration of a set of possible configurations.

The code plays with the values of macros $m1., $m2. and $m3. so that it tries 8 different combinations.

The 8 corresponding CSD are written in the directory where lives the original CSD. For each of these files, a wave file is rendered in SFDIR.

     <ELISP> ;;; [load] - [collapse/unfold] - [save] - [EVAL] - [;EVAL]
     (let ((cscsd-current-processing "csound wav")
           (cscsd-call-csound-always-sync t))
       ;; the let statement gives the correct options to csound
       ;; and ensure that csound will not be executed asynchronously
       (dotimes (i1 2 3)
         (dotimes (i2 2 3)
           (dotimes (i3 2 3)
     	(let* ((m1 (+ 2 i1))
     	       (m2 (+ 1 i2 m1))
     	       (m3 (+ 1 i3 m2)))
     	  (cscsd-set-macro-def "m1" m1)
     	  (cscsd-set-macro-def "m2" m2)
     	  (cscsd-set-macro-def "m3" m3)
     	  (let ((csd-file-name (expand-file-name
     				(format "example%d-%d-%d.csd" m1 m2 m3)
     				(file-name-directory (buffer-file-name)))))
     	    (write-region (point-min) (point-max) csd-file-name)
     	    (message "processing m1=%d m2=%d m3=%d ..." m1 m2 m3)
     	    (cscsd-process csd-file-name)))))))
     </ELISP>
     
     <CsoundSynthesizer>
     <CsInstruments>
     #define m3 #8#
     #define m2 #4#
     #define m1 #2#
     
     ; ************************************************************************
     ; ACCCI:      02_43_1.ORC
     ; timbre:     tibetan chant
     ; synthesis:  additive same units(02)
     ;             basic instrument with minimal differences in frequency(43)
     ;             arpeggio instrument by Risset
     ; source:     Phase6, Lorrain(1980); Boulanger(1990): risset1.orc
     ; coded:      jpg 9/93
     
     sr = 44100
     kr  =  441
     ksmps= 100
     nchnls = 2
     
     instr 1; *****************************************************************
     idur  = p3
     iamp  = p4/9
     ifq   = p5
     ioff1 = p6
     ioff2 = $m1.*p6
     ioff3 = $m2.*p6
     ioff4 = $m3.*p6
     irise = p7
     idec  = p8
     
        ae  linen   iamp,irise,idur,idec
     
        a1  oscili  ae, ifq, 1
        a2  oscili  ae, ifq+ioff1, 1  ; nine oscillators with the same ae
        a3  oscili  ae, ifq+ioff2, 1  ; and waveform, but slightly different
        a4  oscili  ae, ifq+ioff3, 1  ; frequencies create harmonic arpeggio
        a5  oscili  ae, ifq+ioff4, 1
        a6  oscili  ae, ifq-ioff1, 1
        a7  oscili  ae, ifq-ioff2, 1
        a8  oscili  ae, ifq-ioff3, 1
        a9  oscili  ae, ifq-ioff4, 1
     
        outs1   a1+a2+a3+a4+a5+a6+a7+a8+a9
     
     endin
     
     
     instr 2; *****************************************************************
     idur  = p3
     iamp  = p4/9
     ifq   = p5
     ioff1 = p6
     ioff2 = $m1.*p6
     ioff3 = $m2.*p6
     ioff4 = $m3.*p6
     irise = p7
     idec  = p8
     
        ae  linen   iamp,irise,idur,idec
     
        a1  oscili  ae, ifq, 1
        a2  oscili  ae, ifq+ioff1, 1  ; nine oscillators with the same ae
        a3  oscili  ae, ifq+ioff2, 1  ; and waveform, but slightly different
        a4  oscili  ae, ifq+ioff3, 1  ; frequencies create harmonic arpeggio
        a5  oscili  ae, ifq+ioff4, 1
        a6  oscili  ae, ifq-ioff1, 1
        a7  oscili  ae, ifq-ioff2, 1
        a8  oscili  ae, ifq-ioff3, 1
        a9  oscili  ae, ifq-ioff4, 1
     
        outs2   a1+a2+a3+a4+a5+a6+a7+a8+a9
     
     endin
     </CsInstruments>
     
     <CsScore>; ************************************************************************
     ; ACCCI:      02_43_1.SCO
     ; coded:      jpg 9/93
     
     
     ; GEN functions **********************************************************
     
     ; carrier
     f1 0 1024 10 .3 0 0 0 .1 .1 .1 .1 .1 .1
     
     
     ; score ******************************************************************
     
     ;    start   idur  iamp   ifq     ioff   irise   idec
     i1	0	35	8000	110	0.03	0.07	21
     i1	20	20	9600	110	0.04	2	4
     i1	28	30	8000	220	0.04	3	6
     i1	32.1	23	8000	110	0.03	2.3	4.6
     i2	5	20	9600	55	0.02	0.04	12
     i2	20	15	8000	220	0.05	1.5	3
     i2	32	26	9600	110	0.025	2.6	5.2
     i2	36	22	8000	55	0.01	0.04	13
     e
     
     </CsScore>
     </CsoundSynthesizer>


Next: , Previous: Embedded elisp, Up: Top

12 CSD meta-controls

Csound-x defines a specific type of comment line in both orchestra and score sections. Those comments begins with ;| and the following keywords are interpreted as a directive for “meta-control”, that is a control flow or editing structure which has no meaning at the csound langage level and only makes sense for Emacs.

Once defined, such a control structure can be operated from the first part of the “CSD” menu and notably from the “Meta-setting” submenu.


Next: , Previous: CSD meta-controls, Up: CSD meta-controls

13 Meta menus and toggles

The following meta-comments pairs can be used to easily comment out parts of the CSD:

     ;|menu
     ;|endmenu
     
     ;|toggles
     ;|endtoggles

See Meta settings tutorial.


Next: , Previous: Meta menus and toggles, Up: CSD meta-controls

14 Public sections

The meta-comments pair

     ;|begpublic SomeName
     ;|endpublic

enclose a part of the CSD which is supposed to be often tweaked by the composer.

When such public sections appear in a CSD, the “CSD” menu propose an item “Public mode”. This builds and display a “public interface” frame for the CSD, where only the public sections are visibles.

Use item “Full editing mode” to restore the initial display.


Next: , Previous: Public sections, Up: CSD meta-controls

15 CSD snapshots

Snapshots are <ELISP> areas (see Embedded elisp) which, when they are evaluated, restore the values for macros, meta-menus and toggles in the CSD.

Use "CSD -> Meta-Settings -> take a snapshot" to create a new snapshot; you will be prompted for a name in the minibuffer.

Use the submenu "CSD -> Meta-Settings -> restore snapshot ->" to override the current settings with the recorded ones.

See Meta settings tutorial.


Previous: CSD snapshots, Up: CSD meta-controls

16 Meta settings tutorial

Letīs start from the following composition from the Amsterdam catalog of Csound instruments. If you are reading this in an emacs buffer, just click anywhere in the code below and do `M-x cscsd-at-point' in order to have the CSD at hand. Here is the code:

     <CsoundSynthesizer>
     <CsInstruments>; ************************************************************************
     ; ACCCI:      02_43_1.ORC
     ; timbre:     tibetan chant
     ; synthesis:  additive same units(02)
     ;             basic instrument with minimal differences in frequency(43)
     ;             arpeggio instrument by Risset
     ; source:     Phase6, Lorrain(1980); Boulanger(1990): risset1.orc
     ; coded:      jpg 9/93
     
     sr = 44100
     kr  =  441
     ksmps= 100
     nchnls = 2
     
     instr 1; *****************************************************************
     idur  = p3
     iamp  = p4/9
     ifq   = p5
     ioff1 = p6
     ioff2 = 2*p6
     ioff3 = 3*p6
     ioff4 = 4*p6
     irise = p7
     idec  = p8
     
        ae  linen   iamp,irise,idur,idec
     
        a1  oscili  ae, ifq, 1
        a2  oscili  ae, ifq+ioff1, 1  ; nine oscillators with the same ae
        a3  oscili  ae, ifq+ioff2, 1  ; and waveform, but slightly different
        a4  oscili  ae, ifq+ioff3, 1  ; frequencies create harmonic arpeggio
        a5  oscili  ae, ifq+ioff4, 1
        a6  oscili  ae, ifq-ioff1, 1
        a7  oscili  ae, ifq-ioff2, 1
        a8  oscili  ae, ifq-ioff3, 1
        a9  oscili  ae, ifq-ioff4, 1
            outs1   a1+a2+a3+a4+a5+a6+a7+a8+a9
     
     endin
     
     
     instr 2; *****************************************************************
     idur  = p3
     iamp  = p4/9
     ifq   = p5
     ioff1 = p6
     ioff2 = 2*p6
     ioff3 = 3*p6
     ioff4 = 4*p6
     irise = p7
     idec  = p8
     
        ae  linen   iamp,irise,idur,idec
     
        a1  oscili  ae, ifq, 1
        a2  oscili  ae, ifq+ioff1, 1  ; nine oscillators with the same ae
        a3  oscili  ae, ifq+ioff2, 1  ; and waveform, but slightly different
        a4  oscili  ae, ifq+ioff3, 1  ; frequencies create harmonic arpeggio
        a5  oscili  ae, ifq+ioff4, 1
        a6  oscili  ae, ifq-ioff1, 1
        a7  oscili  ae, ifq-ioff2, 1
        a8  oscili  ae, ifq-ioff3, 1
        a9  oscili  ae, ifq-ioff4, 1
            outs2   a1+a2+a3+a4+a5+a6+a7+a8+a9
     endin
     </CsInstruments>
     
     <CsScore>; ************************************************************************
     ; ACCCI:      02_43_1.SCO
     ; coded:      jpg 9/93
     
     
     ; GEN functions **********************************************************
     
     ; carrier
     f1 0 1024 10 .3 0 0 0 .1 .1 .1 .1 .1 .1
     
     
     ; score ******************************************************************
     
     ;    start   idur  iamp   ifq     ioff   irise   idec
     i1	0	35	8000	110	0.03	0.07	21
     i1	20	20	9600	110	0.04	2	4
     i1	28	30	8000	220	0.04	3	6
     i1	32.1	23	8000	110	0.03	2.3	4.6
     i2	5	20	9600	55	0.02	0.04	12
     i2	20	15	8000	220	0.05	1.5	3
     i2	32	26	9600	110	0.025	2.6	5.2
     i2	36	22	8000	55	0.01	0.04	13
     e
     
     </CsScore>
     </CsoundSynthesizer>

We are going to transform this into a template allowing an exploration of the algorithm. The instruments (identical, except from their ouput channel) are very simple: a reference oscillator at frequency p5 is doubled by height extra oscillators whose frequencies are slight variations of p5 controlled by p6. Given p6, the set of shifted frequencies is hardcoded: p5+p6, p5+2*p6, p5+3*p6, p5+4*p6, p5-p6, p5-2*p6, p5-3*p6 and p5-4*p6

Using the "macroify region" function (See The CSD menu.), it is easy to transform the CSD so that the p6 multipliers are now defined by the macros m1, m2 and m3, so that we obtain:

     <CsoundSynthesizer>
     <CsInstruments>
     #define m3 #4#
     #define m2 #3#
     #define m1 #2#
     
     ...
     
     instr 1
     idur  = p3
     iamp  = p4/9
     ifq   = p5
     ioff1 = p6
     ioff2 = $m1.*p6
     ioff3 = $m2.*p6
     ioff4 = $m3.*p6
     irise = p7
     idec  = p8
     
     ...
     
     instr 2
     idur  = p3
     iamp  = p4/9
     ifq   = p5
     ioff1 = p6
     ioff2 = $m1.*p6
     ioff3 = $m2.*p6
     ioff4 = $m3.*p6
     irise = p7
     idec  = p8
     
     ...
     

Now let's click on "CSD -> Meta-Settings -> take a snapshot"; we give it the name "original" at the minibuffer.

Here is what gets inserted somewhere at the beginning of the buffer:

     
     <ELISP> ;SNAPSHOT: original [export] [restore] [see/hide]
     (require 'csound-eel)
     (cseel-restore-snapshot '((:define "m3" :value "4" :in orc) (:define "m2" :value "3" :in orc) (:define "m1" :value "2" :in orc)))
     </ELISP>
     
     
     <CsoundSynthesizer>
     #define m3 #4#
     #define m2 #3#
     #define m1 #2#
     
     ...
     

The [...] parts in the first line should appear as buttons. If for some reason it is not the case, then clicking “EEL -> Wake up embedded buttons” should do the trick.


Now when clicking on the [restore] button, m1, m2 and m3 will get back to their original values.

Restoring a snapshot is also possible from the "Settings" menu, where a "Restore snapshot" submenu should appear, providing a list of all defined snapshots in the buffer.


So now we can go on and change the definitions for m1, m2, m3 to, say, 2, 4 and 8. Then, taking another snapshot called "248", we get this:
     
     <ELISP> ;SNAPSHOT: 248 [export] [restore] [see/hide]
     (require 'csound-eel)
     (cseel-restore-snapshot '((:define "m3" :value "8" :in orc) (:define "m2" :value "4" :in orc) (:define "m1" :value "2" :in orc)))
     </ELISP>
     
     <ELISP> ;SNAPSHOT: original [export] [restore] [see/hide]
     (require 'csound-eel)
     (cseel-restore-snapshot '((:define "m3" :value "4" :in orc) (:define "m2" :value "3" :in orc) (:define "m1" :value "2" :in orc)))
     </ELISP>
     
     ...
     

Now, what about having only the upper frequencies added, or maybe only the lower ones ?

We can do so by defining a meta-menu. We just have to replace

            outs1   a1+a2+a3+a4+a5+a6+a7+a8+a9

with

     ;|menu 1Frequencies
     ;|all
            outs1   a1+a2+a3+a4+a5+a6+a7+a8+a9
     ;|upper
     ;        outs1   a1+a2+a3+a4+a5
     ;|lower
     ;        outs1   a1+a6+a7+a8+a9
     ;|endmenu

... and do the same for instrument 2:

     ;|menu 2Frequencies
     ;|all
            outs2   a1+a2+a3+a4+a5+a6+a7+a8+a9
     ;|upper
     ;        outs2   a1+a2+a3+a4+a5
     ;|lower
     ;        outs2   a1+a6+a7+a8+a9
     ;|endmenu
     

The ;|... comments are meta-comments. If you go to the "Meta-Settings" menu, you will see that there are now two more entries: a submenu "1Frequencies" and a submenu "2Frequencies", both providing the items "all", "upper" and "lower". By selecting those items, you actually comment and uncomment the corresponding sections in the CSD.

Note that this is also recorded when snapshotting. Letīs select "upper" in both instruments, then take a new snapshot "248up". Here is the resulting ELISP area:

     <ELISP> ;SNAPSHOT: 248up [export] [restore] [see/hide]
     (require 'csound-eel)
     (cseel-restore-snapshot '((:define "m3" :value "8" :in orc) (:define "m2" :value "4" :in orc) (:define "m1" :value "2" :in orc) (:menu "1Frequencies" :type "menu" :item "all" :active nil) (:menu "1Frequencies" :type "menu" :item "upper" :active t) (:menu "1Frequencies" :type "menu" :item "lower" :active nil) (:menu "2Frequencies" :type "menu" :item "all" :active nil) (:menu "2Frequencies" :type "menu" :item "upper" :active t) (:menu "2Frequencies" :type "menu" :item "lower" :active nil)))
     </ELISP>
     
     ...

One more step: silenting out part of the score. Letīs replace

     ;    start   idur  iamp   ifq     ioff   irise   idec
     i1      0       35      8000    110     0.03    0.07    21
     i1      20      20      9600    110     0.04    2       4
     i1      28      30      8000    220     0.04    3       6
     i1      32.1    23      8000    110     0.03    2.3     4.6
     i2      5       20      9600    55      0.02    0.04    12
     i2      20      15      8000    220     0.05    1.5     3
     i2      32      26      9600    110     0.025   2.6     5.2
     i2      36      22      8000    55      0.01    0.04    13
     e

with

     ;    start   idur  iamp   ifq     ioff   irise   idec
     ;|toggles Score
     ;|i1
     i1      0       35      8000    110     0.03    0.07    21
     i1      20      20      9600    110     0.04    2       4
     i1      28      30      8000    220     0.04    3       6
     i1      32.1    23      8000    110     0.03    2.3     4.6
     ;|i2
     i2      5       20      9600    55      0.02    0.04    12
     i2      20      15      8000    220     0.05    1.5     3
     i2      32      26      9600    110     0.025   2.6     5.2
     i2      36      22      8000    55      0.01    0.04    13
     ;|endtoggles
     e

This gives birth to a new submenu "Score" in "Meta-Settings", where you can choose weither to include the parts for i1 and i2 in the score.

The difference between ;|menu and ;|toggles is that ;|menu allows only one among its items to be selected at a given time.


Our eventual CSD is now a template where structural choices can be performed in both score and orchestra, and where snapshots make it possible to keep at hand as many combinations of such choices and macro settings as we want. All of this being accessible through the "Meta-Settings" menu.

And because everything happens either in comment lines of in XML areas external to the <CsoundSynthesizer> one, the CSD is still acceptable as a plain input file by csound.


Next: , Previous: CSD meta-controls, Up: Top

17 i.el, a library for generating p-fields streams




Basics

This library implements a set of functions making it very easy to compose a monophonic Csound score in one algorithmic shot.

The basic function is 'i, which insert a i-statement at point. Like this:

     (i 3 27 0.5 1500 0.125)
     
     which, as you would expect, inserts:
     
     i 3 27 0.5 1500 0.125

'i always lives in a specific context, which I call a p-fields stream, because its main purpose is to keep a memory of what was previously inserted

For example, 'i has a sibling function called '|i which accepts a partial list of p-fields:

     (|i :dur 0.8)

inserts:

     i 3 27 0.8

... because the implicit top-level stream remembers the previous values of p1 and p2.

Since only p1, p2 and p3 have a defined meaning, the top level stream does not attempt to manage the other p-fields. This has to be done explicitly by defining a local stream:

     (with-pfields-stream '((4 (:pitch 8.01))
                            (5 (:volume 1000))
                            (6 (:pan 0)))
       (|i)
       (|i :start 30 :pitch 8.02)
       (|i :start 35 :volume 1500))
     
     =>
     
     i 3 27 0.8 8.01 1000 0
     i 3 30 0.8 8.02 1000 0
     i 3 35 0.8 8.02 1500 0

What happened here is that p1, p2 and p3 attributes where inherited from the top-level stream, so that again their values are remembered. In this top-level stream, the associated keys are :instr, :start and :dur, with default values 1, 0, 0

To ignore the top-level stream (that's cleaner), just initialize everything:

     (with-pfields-stream '((1 (:instr 10))
                            (2 (:start 0))
                            (3 (:dur 0.5))
                            (4 (:pitch 8.01))
                            (5 (:volume 1000))
                            (6 (:pan 0)))
       (|i)
       (+i :pitch 8.02)
       (+i :volume 1500))
     
     =>
     
     i 10 0 0.5 8.01 1000 0
     i 10 0.5 0.5 8.02 1000 0
     i 10 1 0.5 8.02 1500 0

This example introduces '+i, another sibling of 'i behaving almost exactly like '|i while managing p2 so that the event starts at the end of the previous note.


Note that although the instrument number (p-field 1) may vary, the other p-fields will still have only one current value. This is why I said at the beginning of this page that i.el can be used to generate monophonic scores: each instrument should have its own stream of parameters.

All p-fields values, when set through '|i, '+i and 'with-pfields-stream can also be quoted lisp forms:
     (with-pfields-stream '((1 (:instr 10))
                            (2 (:start 0))
                            (3 (:dur '(+ 0.5 (* 0.001 (random 100)))))
                            (4 (:pitch 8.01))
                            (5 (:volume '(+ 1000 (* 100 (now)))))
                            (6 (:pan '(random 127))))
       (|i)
       (+i :pitch 8.02)
       (+i :volume '(+ 1500 (* 100 (now)))))
     
     =>
     
     i 10	0	0.5950	8.0100	1000	60
     i 10	0.5030	0.5120	8.0200	1050.3000	51
     i 10	1.0690	0.5800	8.0200	1606.9000	28

This example also introduced 'now, a function returning the current value for p2. Here is an example generating longer and longer notes:

     (with-pfields-stream '((1 (:instr 10))
                            (2 (:start 0))
                            (3 (:dur '(+ 0.5 (/ (now) 10))))
                            (4 (:pitch 8.01))
                            (5 (:volume '(+ 1000 (random 300)))))
       (dolist (p '(8.01 8.02 7.11 7.05 5.09 6.00 8.00))
         (+i :pitch p)))
     
     =>
     
     i 10	0	0.5000	8.0100	1120
     i 10	0.5000	0.5500	8.0200	1087
     i 10	1.0500	0.6050	7.1100	1208
     i 10	1.6550	0.6655	7.0500	1252
     i 10	2.3205	0.7320	5.0900	1064
     i 10	3.0526	0.8053	6.0000	1109
     i 10	3.8578	0.8858	8.0000	1176

There are other functions related to p2:

In the following example we jump around in time:
     (with-pfields-stream '((1 (:p1 1))
                            (2 (:p2 150))
                            (3 (:dur 1.5))
                            (4 (:pit 8.01))
                            (5 (:vol 1000)))
        (NOTE "Example")
     
        (dotimes (bof 3)
          (+i :pit 7.11)
          (+i :pit 8.02 :vol ">"))
     
        (end-note "now is bingo")
        (now-> :bingo)
        (+i :dur 3.5)
        (+i :dur 0.8 :vol 1400)
     
        (note "jumping around:")
        (t- 3.5) (|i :dur 2 :vol 1500 :pit 9.00)
        (t+ 35) (|i)
     
        (note "back in time to bingo:")
        (now-be :bingo) (|i)
     
        (end-of-section))

This inserts the following score:

     /* Example */
     
     i 1     150     1.5     7.11    1000
     i 1     151.5   1.5     8.02    >
     i 1     153.0   1.5     7.11    >
     i 1     154.5   1.5     8.02    >
     i 1     156.0   1.5     7.11    >
     i 1     157.5   1.5     8.02    >       ; now is bingo
     i 1     159.0   3.5     8.02    >
     i 1     162.5   0.8     8.02    1400
     ; jumping around:
     i 1     159.0   2       9.0     1500
     i 1     194.0   2       9.0     1500
     ; back in time to bingo:
     i 1     157.5   2       9.0     1500
     e

As you can see, the stream continuity is a textual one, it is not time-wise: going back in time does not restore the previous default p-fields. This is an important point.




— Macro: with-pfields-stream p-fields &rest body

Defines a set of local variables used to maintain a stream of p-fields, then process BODY within that stream. The stream is effected by the insertion functions |i, +i and i

P-FIELDS is the local value of 'pfstream-pf-attributes. Format: '((NP (:KEY DEFAULT)) ...) where DEFAULT is either a number, a string or a quoted form

If it is incomplete, it will inherit its missing attributes from the value of 'pfstream-pf-attributes in the outside scope. The top level scope (global) only defines p1, p2 and p3


— Function: i &rest p-fields

Insert an i-statement at point


— Function: |i &rest fields-plist

Insert an i-statement at point, using keys to identify the changing p-fields. The other p-fields values are inherited from the local stream


— Function: +i &rest fields-plist

Same as |i, only increments the current p2 by the current p3




The following functions are only valid within a `with-pfields-stream' body. This allows for short and simple names without the risk of a name clash. You may use `pfstream-defun' to define a new function of this kind.

— Function: now

return the current p2 value


— Function: then

return the current p2+p3 value


— Function: now-be time

set current p2 to TIME, a number or a key in 'pfstream-time-markers


— Function: t+ time

set current p2 plus TIME, a number or a key in 'pfstream-time-markers


— Function: t- time

set current p2 minus TIME, a number or a key in 'pfstream-time-markers


— Function: now-> key

associate current p2 to KEY in 'pfstream-time-markers


— Function: then-> key

associate current p2+p3 to KEY in 'pfstream-time-markers


— Function: end-note &rest args

insert ARGS as a comment at the end of the previous line


— Function: note &rest args

insert ARGS as a comment line


— Function: NOTE &rest args

insert ARGS as a /* comment */ with empty lines around it


— Function: section

insert a s-statement


— Function: end-of-section

insert a e-statement


— Macro: pfstream-defun name args &rest body

Define a new function valid only within a `with-pfields-stream' body. This macro itself can not be evaluated within a `with-pfields-stream' body !


— Function: pfstream-defalias short-name full-name

Define an alias for function FULL-NAME, valid only within a pfield-stream




Custom keywords

As described in the previous chapter, each p-field is associated to a keyword. It is possible and quite useful to define other keywords, called custom keywords, which are actually macros that expand into property lists, making it possible to set several p-fields at once.

In the following example we define a :side keywords used to set both the volume and the position of the sound:

     (with-pfields-stream '((1 (:p1 1))
                            (2 (:p2 150))
                            (3 (:dur 1.5))
                            (4 (:pitch 8.01))
                            (5 (:volume 1000))
                            (6 (:pan 0)))
       (add-custom-key
         '(:side (:volume 'identity
                  :pan (lambda (v) (/ v 1000.0)))))
       (|i)
       (+i :pitch 8.02 :side 700)
       (|i :pitch 8.05 :side 850))
     
     =>
     
     i 1	150	1.5000	8.0100	1000	0
     i 1	151.5000	1.5000	8.0200	700	0.7000
     i 1	151.5000	1.5000	8.0500	850	0.8500

— Function: add-custom-key new-key-def

Register a new custom keyword for setting pfields in the stream NEW-KEY-DEF is a list (KEY VAL) where VAL is a plist or a function of one variable returning a plist. KEY will be expanded into that plist. when VAL is a function its single argument will be the value associated to KEY when it is invoked."


— Function: add-custom-keys new-key-def-list

Register at once a list of new custom keys




Nested streams

'with-pfields-stream create a new stream by copying all the current stream “memory” (p-fields values, time markers, custom keys) into local variables.

Nesting streams allow any of these values to be temporarily modified, all changes being cancelled when jumping back to the parent stream.

As for the implicit top-level stream, it is buffer local. Still, stream-related operations should always be done within an enclosing 'with-pfields-stream form, so that there is no possible contamination of the top level between different chunks of code.


— Macro: save-stream &rest body

create a new p-field stream with all p-fields values, time markers and custom keys inherited from the current stream. once BODY is evaluated, everything gets restored. equivalent to 'with-pfields-stream with P-FIELDS argument nil


— Macro: save-stream-insert &rest body

create a new p-field stream with all p-fields values, time markers and custom keys inherited from the current stream. once BODY is evaluated, everything gets restored except the current time which is set to the end time of the exited stream.




Score enumeration

The functions i, +i and |i insert an i-statement at point. In some cases though, we may want to defer the insertion. We call “score line” an expression which, when evaluated, does insert an i-statement.

So '(i 1 0 5 200) or '(+i) are score lines.

A list of score lines is a score. Two powerful macros handles scores and score lines:

— Macro: along-score spec &rest body

SPEC is a list (VAR-SYM SCORE [INDEX-SYM] [SCORE-SYM]) evaluate BODY with VAR taking in turn all note values in SCORE (a list) the macro optionaly binds one or two symbols in the scope of BODY: INDEX-SYM is the position of VAR in SCORE (a number starting at 0) SCORE-SYM is bound to SCORE thus VAR is always equal to (nth <INDEX-SYM> <SCORE-SYM>)


— Macro: score-line event &rest plist

Modify EVENT (a score-line) with PLIST, then evaluate the result. Thus (score-line '(+i amp: 200) :dur 1) is like (+i :amp 200 :dur 1) Note that (score-line 'a :vol 127) or (score-line '(i 1 0 2 500)) are also legal syntaxes


'i> is an alias for 'score-line

example:
     (with-pfields-stream '((4 (:amp 0))
                            (5 (:vol 0)))
       (along-score (n '((i 1 0 5 150 100)
                         (+i :amp 200)
                         (|i :vol 63)))
       (i> n :duration 8)
       (end-note n)))
     
     =>
     
     i 1	0	8	150	100	; (i 1 0 5 150 100)
     i 1	8	8	200	100	; (+i :amp 200)
     i 1	8	8	200	63	; (|i :vol 63)



Direct access to p-fields

At times it is very useful to read the current value of a p-field, or to change it. This can be done with the following functions:


— Function: current-pfield p-field

return the current value of P-FIELD (a number or its associated key) in the stream.

note that when it is a lisp form, it is not returned as such: intead, its evaluation as the body of a lambda expression is returned.

use 'current-pfield-form if you want the quoted form itself.


— Function: current-pfield-form p-field

return the current value of P-FIELD (a number or its associated key) in the stream.

when the current value of a p-field is a quoted lisp form, it is returned as such.

use 'current-pfield if you want its current evaluation instead


— Function: set-pfield p-field val

set the current value of P-FIELD (a number or its associated key) to VAL (a number or a string or a quoted form)

this function does not accept a custom key: use 'set-in-stream instead


— Function: set-in-stream &rest key-val-plist

set the current values for KEYs to VALs, expanding a KEY if it is a custom key




It is also possible to query a score line (see above for a definition of this term) for the value it defines for a given keyword:
— Function: score-line-pfield event pf

return the value for pfield PF (a number or a key) as associated in EVENT (an i-statement). return nil if PF is not explicitely defined in EVENT. the custom keywords are not expanded; PF may be a custom keyword


— Function: pfield event pf

return the value for pfield PF (a number or a key) in EVENT (an i-statement). if PF is not explicitely defined, check if it appears when expanding the custom keys. if PF can still not be found in EVENT, return its current value in the stream . PF should not be a custom keyword


Next: , Previous: The i library, Up: Top

18 k.el, extending i.el with MIDI streams




k.el is an extension of i.el that defines a specific format for musical notes based on Keykit representation of MIDI data.

In Keykit, musical phrases are represented like this: `ao2v100, e g, f+`

Here the first note has an explicit octave and volume. The following notes inherit from these values. So this format is actually very close to what I called a p-field stream in the discussion of i.el

Keykit notes, because they represent MIDI data, have specific ranges for volume and pitch: those are always integers from 0 to 127. Duration is also expressed with integers, called clicks, with 192 clicks in one second.

The macro 'with-keykit-stream defines and initialises a mapping by the mean of custom keys, so that notes can explicitely refer to :pit :dur :vol :ch and :time, using the Keykit format.

A large set of functions provide a wealth of shortcuts to write such notes. In the following we use four different ways to insert the same musical phrase:

     ;; explicit invocation of '|i and '+i
     (with-keykit-stream
             (|i :pit 57 :dur 150 :vol 90)
             (+i :pit 58)
             (+i :pit 59 :ch 2))
     
     ;; using Keykit format for pitches
     ;; a note prepended by > is delayed to the end of the previous note
     (with-keykit-stream
             (ao2 :dur 150 :vol 90)
             (>b-)
             (>p59 :ch 2))
     
     ;; with macro 'along-score:
     (with-keykit-stream
      (along-score (n '(ao2d150v90 >b- >p59c2))
        (i> n)))
     
     ;; with macro 'along-keyphrase:
     (with-keykit-stream
      (along-keyphrase (n "'ao2d150v90, b-, bc2'")
        (i> n)))

'along-score is the most powerful enumerating macro: it accepts about any format for notes, as illustrated in the following example
     (with-keykit-stream
      (along-score (n '((i 1 10)
                        >ao2d150v90
                        (ao3d120 :vol 110)
                        >b-
                        >p59c2
                        +i
                        (i 3 14 :vol 80)))
        (i> n)))
     
     =>
     
     i 1	10	0.5000	440.0000	4960.6299
     i 1	10.5000	0.7813	220.0000	7086.6142
     i 1	10.5000	0.6250	440.0000	7086.6142
     i 1	11.1250	0.6250	466.1638	7086.6142
     i 2	11.7500	0.6250	246.9417	7086.6142
     i 2	12.3750	0.6250	246.9417	7086.6142
     i 3	14	0.6250	246.9417	6299.2126

'along-keyphrase actually handles any Keykit expression returning a phrase as argument. That expression is send to lowkey, evaluated there and the result is parsed. So we can write things like:
     (with-keykit-stream
      (along-keyphrase (n "fractal('ao2d600v90, b-, bc2',2)")
        (i> n)))

The mapping from :vol and :pit is set by default within 'with-keykit-stream, and will need to be defined again in order to fit the orchestra. This can be done either by using functions 'add-custom-key or 'add-custom-keys, like this:

     (add-custom-keys
      '((:vol (:amp (lambda (v) (midi-to-range v 0 300))))
        (:pit (:pitch 'midi-to-pch))))

Equivalent and more convenient, we have functions `kstream:vol and 'kstream:pit

     (kstream:vol '(:amp (lambda (v) (midi-to-range v 0 300))))
     (kstream:pit '(:pitch 'midi-to-pch))



Reference

— Macro: with-keykit-stream &rest body

Defines a pfield-stream adapted to the transcription of Keykit phrases into a score


— Function: kstream:vol sexp

Perform (add-custom-key (list :vol SEXP))


— Function: kstream:pit sexp

Perform (add-custom-key (list :pit SEXP))


— Macro: along-keyphrase spec &rest body

SPEC is a list (VAR KEYPHRASE [INDEX-SYM] [SCORE-SYM]) evaluate BODY with VAR taking in turn all note values in KEYPHRASE (a Keykit expression) the macro optionaly binds one or two symbols in the scope of BODY: 'INDEX-SYM is the order position of VAR in KEYPHRASE (starting at 0) 'SCORE-SYM is the computed list of all notes in KEYPHRASE thus VAR is always equal to (nth <INDEX-SYM> <SCORE-SYM>)


— Macro: along-KeyPhrase spec &rest body

...


— Macro: along-MIDIfile spec &rest body

...


Next: , Previous: The k library, Up: Top

19 Composing directly in Emacs Lisp

Csound-x can work upside-down: instead of editing Csound files you can directly compose in Emacs Lisp in a way that hides the underlying CSD structure:

     (csl-play-composition
      (csound-composition
        :ftables (1 :sin 8192)
        :instr 1
        [out (oscili :arate (oscili :krate p4 1/p3 p7) p5 p6)]
        :score (insert "f 2 0 513 5 1 12 1024 500 1" ?\n)
        :i-stream
        (i 1 0 4 8000 440 1 2)
        (loop for h in '(2200 600 215 1852 990)
              for d in '(2 2.5 2 1.5 4)
              do (+i :p5 h :p3 d))))

... this is very much a work in progress and still subject to important changes. please do not rely on the current API.

see doc strings, tests and examples in csound-lsp.el for details


Next: , Previous: Csound Elisp, Up: Top


Next: , Previous: Concept index, Up: Top

Command Index

Commands available via M-x prefix.


Next: , Previous: Command index, Up: Top

Variable Index

Csound-x variables and hooks


Next: , Previous: Variable index, Up: Top

Function Index

Csound-x public functions


Previous: Function index, Up: Top

Known bugs and incompatibilities


MMM-mode is not kind with imenu. Turning on the “Index” menu for all emacs-lisp-mode buffers will cause troubles at time.

Fix: deactivate imenu for emacs-lisp-mode buffers