Karim Barkati

Pierre Jouvelot

A Synchronous Programming in Audio Processing: A Lookup Table Oscillator Case Study

Keywords: A.1 [General Literature]: Introductory and Survey, C.3 [Specialpurpose and Application-based Systems]: Real-time and Embedded Systems, Signal Processing Systems, D.1.3 [Programming Techniques]: Concurrent Programming-Parallel programming, D.1.m [Programming Techniques]: Miscellaneous, D.2.11 [Software Engineering]: Software Architectures, D.3.2 [Language Classifications]: Concurrent, Distributed, and Parallel Languages, Data-flow Languages, Specialized Application Languages, Very High-Level Languages, D.3.3 [Programming Languages]: Language Constructs and Features, E.1 [Data Structures]: Arrays, H.5.5 [Information Interfaces and Presentation]: Sound and Music Computing-Signal analysis, synthesis, and processing, Systems, J.5 [Arts and Humanities]: Performing Arts, J.7 [Computers in Other Systems]: Real Time, K.2 [Computing Milieux]: History of Computing Synchronous programming languages, Music programming languages, Computer music, Signal processing, Timing

The adequacy of a programming language to a given software project or application domain is often considered a key factor of success in software development and engineering, even though little theoretical or practical information is readily available to help make an informed decision. In this paper, we address a particular version of this issue by comparing the adequacy of general-purpose synchronous programming languages to more domain-specific languages (DSL) in the field of computer music. More precisely, we implemented and tested the same lookup table oscillator example program, one of the most classical algorithms for sound synthesis, using a selection of significant synchronous programming languages, half of which designed as specific music languages -Csound, Pure Data, SuperCollider, ChucK, Faust -and the other half being general synchronous formalisms -Signal, Lustre, Esterel, Lucid Synchrone and C with the OpenMP Stream Extension (Matlab/Octave is used for the initial specification). The advantages of these two approaches are discussed, providing insights to language designers and possibly software developers of both communities regarding programming languages design for the audio domain.

INTRODUCTION

The understanding of the existence of a close relationship between music and mathematics has been mentioned since the ancient Greeks. This is therefore not surprising that programming language designers have considered the musical domain as a venue of choice for their investigations from the early days of the field of computing [START_REF] Van Roy | Programming Paradigms for Dummies: What Every Programmer Should Know[END_REF]: programming is indeed a constructive approach to mathematical reasoning. There are of course multiple ways to use programming languages in music applications, from low-level audio processing to more abstract music notation manipulation processes to the higher sphere of music composition frameworks.

Current digital audio applications are often based on the algorithmic real-time processing of streams of sound samples; these signals are subject to strong timing requirements since latencies and delays in music signals are easily detectable even by untrained human ears. Such constraints call for programming languages that are able to manage somewhat significant data throughputs while enforcing timing properties. Even though traditional programming languages offer means of addressing timing issues within programs, e.g., via the sleep system call in C or clock in C++, they do not consider the notions of time and data streams as the foundation for their design paradigm, syntax and semantics. The goal of synchronous and music languages is in fact to hide low-level implementation details to the programmer as much as possible, narrowing the semantic gap between specification and implementation. For instance, in all music languages, one only needs to specify what processing actions are requested for each audio sample. All the management of low-level issues such as system calls, buffers, callbacks or audio frames is performed via the compiler and run-time system.

Moreover, most audio processing applications happen to be modeled as large sets of concurrent interacting dataflow processes. The specification of the behaviors and synchronization patterns of such computations would be unwieldy at best using traditional all-purpose languages, in which difficult-to-track "temporal bugs" [START_REF] Simon | Synchronous programming of automatic control applications using OrCAD and Esterel[END_REF], such as race conditions or deadlocks, often occur. Traditional languages seldom provide strong formal guarantees regarding timing constraints for concurrent processes operating over sampled input and output streams, as opposed to synchronous and music languages: correctness, ease of programming and other benefits are what such specific languages provide. Finally, the growing importance of the practice of "livecoding" [START_REF] Nilson | Live coding practice[END_REF], where computer musicians perform on stage by programming and running code snippets on the fly, calls also for lightweight and dedicated programming formalisms.

A family of programming languages happens to have been developed to specifically deal with timing issues, in particular for embedded and time-critical systems: synchronous languages [Benveniste and Berry 1991b;[START_REF] Benveniste | The synchronous languages twelve years later[END_REF]]. This particular programming paradigm is based on the key idea of synchronizing concurrent computing processes on clocks, while ensuring the mathematical correctness of the resulting programs, obviously needed given the target domains. The use of clocks corresponds to a discretization of the time domain, and thus of the number of states a programmer or an automatic correctness prover might have to consider when trying to ensure the correctness of source code. Traditional programming models adopt what amounts to a continuous time domain vision, more prone to the introduction of subtle run-time errors.

Independently, the computer music community has been working on music-specific languages, initially centered on designing sound generators, seen as virtual instruments; the issues of time and processes were also addressed there, but in less formal ways and more as an afterthought in the language design process. The relationship of synchronous languages with the temporal structure of music and real-time audio computing appears thus to be manifest and justifies the current interest of the music community for the synchronous paradigm.

The purpose of this paper is to provide a comparative survey of the existing portfolio of major synchronous programming languages that can be used in the specific field of audio processing. We believe such an analysis is particularly pertinent today, since this domain has seen a recent significant growth both in the industrial and research

Synchronous Programming In Audio Processing: A Lookup Table Oscillator Case Study

A:3 worlds, with the widespread use of gadgets such as MP3 players or the introduction of new programming languages such as Faust [START_REF] Orlarey | FAUST: an Efficient Functional Approach to DSP Programming[END_REF] or ChucK [START_REF] Wang | ChucK: A Concurrent, On-the-fly Audio Programming Language[END_REF]]. This survey adopts a two-pronged approach: we look both at key music programming languages, i.e., audio-specific languages designed in the computer music community, and general signal-processing programming languages to see how they relate to each other while adopting, with some variations, the synchronous trait.

Our comparison work focuses on design issues. Both synchronous and computer music programming languages strive to help lower the semantic gap between informal specifications and their formal program development. Even though other facets of programming languages such as their performance, implementation details, portability or availability might justify other comparison studies, we believe that design choices are in fine the key drivers in the acceptability, success and ultimately sustainability of programming languages; they deserve an in-depth analysis of their own. We adopt a pragmatic approach when looking at these design issues: we use the same running example throughout the article, namely the implementation of a lookup table oscillator. For each implementation, we stick as much as possible to the programming style of the corresponding language in order to highlight its idiosyncratic design aspects.

We believe our work can be of help to language designers interested in the handling of time and/or audio in programming languages, since, in particular for DSL1 applications, cross-fertilization between languages via the borrowing of existing language features is a common way to improve language designs. Moreover, software developers and project managers who need to decide which language is best adapted to a given digital audio project may also find our survey of interest, in particular the audio language part. Indeed, the adequacy of a programming language to a project is often considered a key factor of success in software development, even though little theoretical or practical information is readily available to help make an informed decision. Even though all the programs in this paper have been tested and run, we do not expect our readers, whom we assume have already some working knowledge of current programming languages, to understand all the gory details of these implementations. We hope though that they will get from our work (1) a feel for the design principles of each language, (2) a new perspective on how wide the spectrum of design choices is when trying to deal with timing issues, and possibly (3) a keen interest in delving further into one or the other of these key representative languages.

The structure of the paper is the following. Section 2 provides a brief general overview of the most prominent music and synchronous programming languages. Section 3 contains a description of our running example, which we consider a typical use case for most current audio applications; we provide both an informal and a formal, in Matlab/Octave, specification of our target program, osc, a standard wave synthesis algorithm. The two following sections, namely Section 4 for music-specific languages and Section 5 for synchronous languages, present our attempts at implementing osc in a few selected languages. For each one of these languages, we use the same presentation format: (1) a brief overview introduces the language -using the own words of its author(s) -, (2) the osc example we coded in this particular formalism and (3) a set of notes, when we felt that some explanations were needed for what we assumed would be the most difficult programming details to understand. Section 6 puts our different implementations in perspective, highlighting the specificities of the various approaches and the opportunities for mutual interactions between synchronous and computer music language designs. We conclude and suggest future work in Section 7.

THE SYNCHRONOUS PARADIGM AND COMPUTER MUSIC

From theoretical time-complexity issues to user interaction management, the concept of time has a structuring effect on the way computer technology impacts the programming world. In languages specifically dedicated to music programing, music events are expressed along strict timing constraints. Synchronous general-purpose languages also consider (logical) time, along which control and computation are scheduled, as a key design ingredient; they adhere to the "synchronous hypothesis", which emphasizes time constraints and determinism. Even though developed within a totally different research community, music-specific languages also follow this synchronous hypothesis. We survey below these two approaches, and end this section with the list of key representative languages we use in the remaining of this paper.

Computer Music Languages

Even though digital music sequencing tools such as, nowadays, Steinberg Cubase or Apple Logic provide friendly ways to edit and synchronize music sequences on a fixed timeline, more refined timing constraints and higher-level abstraction mechanisms have been asked for by artists over the years, calling for programming mechanisms that go way beyond those offered in sequencers. These issues, among others, are addressed by the vibrant and dynamic research field of computer music, one of the oldest application domains of computers. Started in the late 1950s on mainframes, computer music has two main branches [START_REF] Loy | Programming languages for computer music synthesis, performance, and composition[END_REF]: computer-aided composition (CAC) and digital audio processing. For this study, we are interested in the latter.

The CAC branch, which usually aims at producing scores, deals mostly with the note paradigm, using a symbolic approach where the characteristics of notes (e.g., their pitch and time location) and not their actual sound are encoded. This programming path started in 1956 with the MUSICOMP2 language of Lejaren Hiller and Robert Baker (both chemists at that time) at the University of Illinois using an Illiac I [START_REF] Baker | MUSICOMP: MUsic Simulator-Interpreter for COMpositional Procedures for the IBM 7090[END_REF][START_REF] Hiller | Computer Cantata: A study in compositional method[END_REF]. Main CAC languages include PatchWork [START_REF] Laurson | PatchWork, a graphical language in PreForm[END_REF], Common Music [START_REF] Taube | Common Music: A music composition language in Common Lisp and CLOS[END_REF]], Haskore [START_REF] Hudak | Haskore music notation: An algebra of music[END_REF], Elody [START_REF] Orlarey | Elody: A Java + MidiShare based music composition environment[END_REF], OpenMusic [START_REF] Assayag | Computer-assisted composition at IR-CAM: from PatchWork to OpenMusic[END_REF] and PWGL [START_REF] Laurson | An overview of PWGL, a visual programming environment for music[END_REF]].

The digital audio processing branch is mostly focused on the sound paradigm, using signal processing and physical modeling approaches; the overall goal here is to synthesize and process files or streams of audio samples, while moving in the mid-1980s to a more "real-time" mode better fitted to live performances. This branch started around 1957 with the MUSIC I language of Max Mathews [START_REF] Mathews | The technology of computer music[END_REF], then an engineer at the Bell Telephone Laboratories (Murray Hill, New Jersey), on an IBM 704; at the time, hours of computation were necessary to get a few seconds of sound. The concept of unit generator, implemented in Mathews' Music-N languages, will prove itself a pervasive concept in audio signal processing, both in computer music languages and hardware synthesizers.

We classify below several significant audio synthesis languages and systems, hence providing a global picture of the domain -note though that some boundaries may be somehow artificial as some languages belong to several categories: Textual Languages. Music-N family languages (I, II, III, IV, V) [START_REF] Mathews | The technology of computer music[END_REF], Csound [START_REF] Vercoe | Csound: a manual for the audio processing system and supporting programs with tutorials[END_REF][START_REF] Boulanger | The Csound Book[END_REF], SAOL [START_REF] Scheirer | SAOL: The MPEG-4 structured audio orchestra language[END_REF], Faust [START_REF] Orlarey | FAUST: an Efficient Functional Approach to DSP Programming[END_REF], Nyquist [START_REF] Dannenberg | Machine tongues XIX: Nyquist, a language for composition and sound synthesis[END_REF]], SuperCollider [Mc-Cartney 1996], ChucK [START_REF] Wang | ChucK: A Concurrent, On-the-fly Audio Programming Language[END_REF], Impromptu [START_REF] Sorensen | Impromptu: An interactive programming environment for composition and performance[END_REF]];

Visual Programming Environments. Max/MSP [START_REF] Puckette | Combining event and signal processing in the MAX graphical programming environment[END_REF][START_REF] Zicarelli | An extensible real-time signal processing environment for Max[END_REF]], Pure Data [START_REF] Puckette | Pure Data: Another Integrated Computer Music Environment[END_REF], jMax [START_REF] Déchelle | jMax: an environment for real-time musical applications[END_REF]], Open Sound World [Chaudhary et al. 2000]; Physical Modeling Systems. Modalys [START_REF] Eckel | Sound synthesis by physical modelling with Modalys[END_REF], Chant [START_REF] Rodet | The CHANT project: from the synthesis of the singing voice to synthesis in general[END_REF], Genesis/Cordis-Anima [START_REF] Castagné | GENESIS : a friendly musician-oriented environment for mass-interaction physical modeling[END_REF][START_REF] Cadoz | CORDIS-ANIMA: a Modeling and simulation system for sound and image synthesis: the general formalism[END_REF]; Miscellaneous. Kyma [START_REF] Scaletti | Kyma: An object-oriented language for music composition[END_REF]] (graphical sound design environment), STK [START_REF] Cook | The synthesis toolkit (STK)[END_REF] (C++ toolkit), CLAM [START_REF] Amatriain | CLAM: A framework for efficient and rapid development of cross-platform audio applications[END_REF], SndObj [START_REF] Lazzarini | The SndObj Sound Object Library[END_REF].

Synchronous Languages

Synchronous programming languages appeared in the early 1980s in France, with Esterel (École des mines de Paris and INRIA, Sophia Antipolis), Lustre (Verimag/CNRS, Grenoble) and Signal (INRIA, Rennes), as an academic research field mixing control theory and computer science [Benveniste and Berry 1991a;[START_REF] Halbwachs | Synchronous Programming of Reactive Systems[END_REF]2005], before becoming of high industrial interest for critical systems [START_REF] Benveniste | The synchronous languages twelve years later[END_REF]] such as those present in avionics, trains and nuclear power plants. The idea of synchrony was arising also through Milner's work on communicating systems [START_REF] Milner | A calculus of communicating systems[END_REF]], AFCET3 's Grafcet [START_REF] Baker | GRAFCET and SFC as Factory Automation Standards Advantages and Limitations[END_REF]] and Harel's Statecharts formalism [START_REF] Harel | Statecharts: A visual formalism for complex systems[END_REF]].

Synchronous languages are high-level, engineer-friendly, robust, specification formalisms, rooted in the concepts of discrete time and deterministic concurrency. Time is usually not explicitly mentioned in the definition of traditional programming languages. Such a notion is however of paramount importance in the design and implementation of data-flow and control software for reactive systems [START_REF] Harel | On the development of reactive systems[END_REF][START_REF] Halbwachs | Synchronous Programming of Reactive Systems[END_REF]]; indeed interactions with external environment processes are there subject to time constraints, memory constraints, security constraints and determinism requirements. Synchronous languages, which strive to reach such demanding objectives, are often equipped with timing and concurrency mathematical models that are structured around automata theory and a typical core hypothesis of bounded calculus and communication between logical instants; this paradigm is called the "synchronous hypothesis" and is typically checked by calculating the worst case execution time. Since the semantics of synchronous languages assumes that computation and communication are performed within logical instants, these languages provide, contrarily to traditional ones, programmers and the running environment explicit access to time, via clocks. Computations are specified with respect to these explicit clocks, ensuring that timing constraints can be stated by programmers and verified by compilers later on.

More specifically, in synchronous languages, time is seen as a succession of shared logical instants generated by regular (hence synchronous) support clocks, which make programs actually move forward. Synchronous programming uses specific programming languages designed to offer a programming paradigm centered on clocks, and clocks only. The overall goal here is not to provide a general-purpose programming set of features, as can be found in traditional languages such as C/C++, that can be used to address any programming issue, but to help with the sole implementation of critical real-time systems that need to satisfy stringent, "hard real-time" timing constraints. The specification and execution of a synchronous program amount, at least in principle, to the sequencing of an infinite loop of tightly time-constrained sets of atomic reactions. All computations and communications must always be performed within one base clock period. This property is the crux of synchronous programming languages design: it ensures that both concurrency, inherent to reactive systems, and determinism, highly desirable for critical systems, are preserved. Traditional, general-purpose programming languages are usually unable to guarantee such a correctness feature, at neither the logical nor the temporal level, while the very model of synchronous languages implementation makes it easier to check both run-time timing load and memory footprint. Moreover, limiting the generality of the programming paradigm ensures that implementations will be closer to specifications, thus increasing readibility, debugging and maintainability.

To illustrate the richness and diversity of the synchronous programming research field, we provide below a list of forty synchronous languages of interest. This list is neither intended to be exhaustive nor limited to a particular paradigm; it is rather a large-spectrum overview, mixing together very different languages toward a taxonomy of a significant set of synchronous and synchronous-oriented languages. We loosely categorized them using the criteria of syntax (textual, graphic), language definition approach (full-fledged or language extension) and application domain specificities (generic, hardware, models):

Textual Languages. Esterel [START_REF] Berry | The ESTEREL synchronous programming language and its mathematical semantics[END_REF], Lustre [START_REF] Caspi | LUSTRE: A declarative language for programming synchronous systems[END_REF], Signal [START_REF] Gautier | Signal: A declarative language for synchronous programming of real-time systems[END_REF][START_REF] Gamatié | Designing embedded systems with the Signal programming language: synchronous, reactive specification[END_REF], ConcurrentML [START_REF] Reppy | Concurrent Programming in ML[END_REF]], Larissa [START_REF] Altisen | Aspect-oriented programming for reactive systems: Larissa, a proposal in the synchronous framework[END_REF]], Lucid Synchrone [START_REF] Caspi | Synchronous Kahn networks[END_REF], Prelude [START_REF] Pagetti | Multi-task implementation of multi-periodic synchronous programs[END_REF], Quartz [START_REF] Schneider | A Verified Hardware Synthesis of Esterel Programs[END_REF]], ReactiveML [START_REF] Mandel | ReactiveML: a reactive extension to ML[END_REF], RMPL [START_REF] Ingham | A Reactive Model-based Programming Language for Robotic Space Explorers[END_REF], SL [START_REF] Boussinot | The SL synchronous language[END_REF], SOL [START_REF] Bharadwaj | SOL: A verifiable synchronous language for reactive systems[END_REF], StreamIt [START_REF] Thies | StreamIt: A Language for Streaming Applications[END_REF], 8 1 /2 [START_REF] Giavitto | A Synchronous Data-Flow Language for Massively Parallel Computers[END_REF]]; Visual Languages and Environments. Argos [START_REF] Maraninchi | The Argos language: Graphical representation of automata and description of reactive systems[END_REF]], Statecharts [START_REF] Harel | Statecharts: A visual formalism for complex systems[END_REF]], SyncCharts [START_REF] André | Representation and analysis of reactive behaviors: A synchronous approach[END_REF]], Argonaute [START_REF] Maraninchi | Argonaute: graphical description, semantics and verification of reactive systems by using a process algebra[END_REF]], Polis [START_REF] Balarin | Hardware-software co-design of embedded systems: the POLIS approach[END_REF]], Polychrony [Le Guernic et al. 2003], Scade [START_REF] Dormoy | Scade 6: a model based solution for safety critical software development[END_REF]], Simulink/Matlab [START_REF] Caspi | From Simulink to SCADE/Lustre to TTA: a layered approach for distributed embedded applications[END_REF]]; Language Extensions. ECL (C)4 [START_REF] Lavagno | ECL: a specification environment for system-level design[END_REF], Jester (Java) [START_REF] Antonotti | JESTER: An Esterel based reactive Java extension for reactive embedded systems[END_REF]], Reactive-C (C) [START_REF] Boussinot | Reactive C: An extension of C to program reactive systems[END_REF]], Real-time Concurrent C (C) [START_REF] Gehani | Real-time concurrent C: A language for programming dynamic realtime systems[END_REF], RTC++ (C++) [START_REF] Ishikawa | An object-oriented real-time programming language[END_REF], Scoop (Eiffel) [START_REF] Compton | SCOOP: An investigation of concurrency in Eiffel[END_REF]], SugarCubes (Java) [START_REF] Boussinot | The SugarCubes tool box: a reactive Java framework[END_REF]]; Hardware Description Languages. Lava [START_REF] Bjesse | Lava: hardware design in Haskell[END_REF]], SystemC [Initiative 2006], Verilog [START_REF] Thomas | The Verilog hardware description language[END_REF], VHDL [IEEE standard 1988]; Models and Intermediate Formats. Averest [START_REF] Schneider | Averest: Specification, verification, and implementation of reactive systems[END_REF], DC+ [START_REF] Pnueli | Translation validation for synchronous languages[END_REF]], OC [START_REF] Girault | A survey of automatic distribution method for synchronous programs[END_REF]], SC [START_REF] Girault | A survey of automatic distribution method for synchronous programs[END_REF]], DC [START_REF] Girault | A survey of automatic distribution method for synchronous programs[END_REF]], CP [START_REF] Girault | A survey of automatic distribution method for synchronous programs[END_REF], SDL [START_REF] Ellsberger | SDL: formal object-oriented language for communicating systems[END_REF], ULM [START_REF] Boudol | ULM: A core programming model for global computing[END_REF]], UML Marte [START_REF] Mallet | On the semantics of UML/MARTE clock constraints[END_REF].

Key Language Representatives

The family of significant synchronous languages dedicated to music is clearly more limited than the one of general purpose languages, although music seems an obvious application field for the synchronous programming paradigm and its associated languages. Indeed, many concurrent processes (associated to instruments or artists) are intimately linked to the audio sampling frequency that drives the production of sound samples. One of our goals with this research work is to illustrate that a bridge can be made between the synchronous and music programming paradigms we just surveyed.

Even though the brief presentation, above, of existing music and synchronous languages is by no means exhaustive, it makes it obvious that these families of languages offer a very wide variety of possible candidates for our comparison survey. To make our use case analysis project realistic, we need to make a selection to end up with a manageable small subset of these languages. We based our selection criteria on the availability of each language and its associated tools, the import of its design principles on the history of the synchronous and computer music paradigms and a rough assessment of the size of its user base. We thus end this section with the selection of the representative languages that are the basis for our use case study, listed in Table I with the name of the main institution where they were created and their authors.

THE OSCILLATOR USE CASE

Our survey of significant technological tools for the synchronous programming of audio applications is grounded on practical terms. We decided to perform for such an analysis a use case study and picked osc, an implementation of a sound oscillator, as our test case. We selected this application since it is particularly simple and can be coded in a few lines, making it a program of choice for a comparison survey tackling multiple languages. This choice is also perfectly adequate on a more functional level, since this simple truncated lookup table oscillator algorithm is particularly significant for the audio domain, being one of the most classical algorithms of the sound synthesis field. Notably, it is also involved in other important computer music algorithms, such as wavetable synthesis, additive synthesis or FM synthesis (frequency modulation). Of course, typical audio processing applications such as delays or reverbs are more complex than our simple osc use case, in particular since many of them can be seen as filters, taking input sample streams and producing modified ones. Dealing with such more involved applications might possibly provide some additional insights into the nature of the relationships linking DSLs and synchronous languages; yet, we believe that the ubiquitous nature of osc in audio processing makes it illuminating enough to expose the gist of each programming language addressed in our survey.

Although it would theoretically be possible to program the algorithm for osc at the same abstraction level for all languages, we felt that such an a priori fair approach would not lead to a convincing comparison. Indeed, by essence, the very concept of DSL has been introduced to provide idioms intending to ease programming. One of the goals of this survey is to compare programming paradigms, and possibly provide a case for the introduction of more domain-specific constructs in languages, including synchronous ones. Using languages, be they domain-specific or synchronous, at their top potential is thus a key ingredient to reaching that goal.

Presentation

The purpose of osc is to output, in a programming language-specific manner, the successive samples of a sinusoidal waveform stored in a vector 5 ; the wave frequency is a parameter of this process, and can be changed at start-up time. The basic idea is to always loop over the same single sinusoidal vector for all frequencies, but to decide which sound samples to output according to what the requested frequency freq is; for instance, picking every other sample will provide a signal with a frequency twice that of the original if the sinusoidal vector is always looped over at the same rate. In more details (see also Figure 1):

-during the initialization stage, one period of the sin function is sampled and tablesize samples are stored in the vector sinwaveform; -the main function osc(freq) loops over this vector indefinitely while outputting the successive sound samples of frequency-dependent phase, i.e., vector index int(phase(freq)), for each time tick; -each phase(freq) is the product of tablesize and one of the steps i(n) defined as i(n) = {i(n-1) + freq/samplingfreq} and i(0) = 0, where {x} denotes the fractional part of any number x and samplingfreq is the audio output sampling frequencythis kind of recursive equation is a typical tenet of both synchronous languages and digital signal processing (DSP) applications; -the audio sample corresponding to each particular phase is provided by the rdtable function, returning sinwaveform[int(phase(freq))]; the integer typecast int computes the integer part of its argument by truncation of the fractional part6 , thus ensuring that table indexes are of integer type; -each sampled data point is finally output, in a more or less platform-specific manner.

sinwavetable[tablesize]

int(phase(freq)) int(phase(freq))

Interface

At the highest level, nine general constants and functions have to be provided to ensure the existence of a working implementation of osc; the corresponding signature is listed in Table II. Of course, depending on the particular programming language and its abstraction level, some of these functions will be indeed visible in the osc program text; for others, they will only be implicitly present in our implementation.

Synchronous Programming In Audio Processing: A Lookup Table Oscillator Case Study

A:9 Environment. In order for osc to be implemented in a particular language, the following features need to be available in the programming environment:

-the two mathematical functions sin and floor (used to compute the fractional part of a number {x} = x -x ); -the ability to perform dynamic reads of tables (vectors of samples); -a looping construct for table initialization and osc.

Usage. The osc process is launched by calling the main function osc with the chosen frequency as argument, e.g., osc(440). In this study, we use a constant frequency value, but ideally the freq argument should be an input signal, i.e, a stream of frequencies, for example [523.25, 587.33, 659.26, ...] -this particular succession of frequencies would in practice yield a sequence of notes, here [C, D, E, ...]. Such an extension would not have a significant impact on the structure of our osc algorithm, and thus our example, kept short due to space limitations, is enough to present the key ingredients of each programming language.

In theory, the osc algorithm never terminates, as it is a synchronous program that, given an input frequency, generates sinusoidal sample values in an output stream. In practice, depending on the language at hand, the user will either have to interrupt the execution after enough samples have been output, in many cases by typing 'ctrl-c', or get a finite vector of outputsize samples. However, even though the output behaviors of our implementations vary according to the language at hand, this is a rather peripheral issue linked to the actual input/output environment used to run our code; this does not significantly alter the synchronous specification of the osc process, which is the focus of interest here.

For the validation of our tests, we computed a reference vector of 200 sound samples; it begins with the following rounded values, corresponding to the 440 Hz diapason at the 44,100 Hz sampling rate: [0.0000, 0.0626, 0.1250, 0.1869, 0.2481, 0.3083, 0.3673, 0.4249, 0.4807, 0.5347, 0.5866, 0.6362, 0.6833, 0.7277, ...]. The output of each implementation has been compared to this reference vector, any mismatch being an indication of something wrong with the corresponding implementation.

Specification

We provide here an implementation of osc using indifferently Octave 7 or Matlab 8 , a well-known "high-level technical computing language and interactive environment for algorithm development, data visualization, data analysis and numeric computation". This straightforward imperative implementation should be easily understood by most readers, and serves here as a more formal specification of our use case. Here, the osc output is the array waveform. § ¤ function [ waveform ] = osc ( f r e q ) t a b l e s i z e = b i t s h i f t ( 1 , 16) ; s a m p l i n g f r e q = 44100; o u t p u t s i z e = 200; t w o p i = 2 * p i ;

indexes ( 1 ) = 0 ; waveform ( 1 ) = 0 ;

f o r i = 1 : t a b l e s i z e sinwaveform ( i ) = s i n ( ( i * t w o p i ) / t a b l e s i z e ) ; end f o r i = 2 : o u t p u t s i z e indexes ( i ) = f r a c p a r t ( ( f r e q / s a m p l i n g f r e q ) + indexes ( i -1) ) ; phase = t a b l e s i z e * indexes ( i ) ; waveform ( i ) = sinwaveform ( u i n t 1 6 ( phase ) ) ; end end

function [ y ] = f r a c p a r t ( x ) y = x -f l o o r ( x ) ; end ¦ ¥

Design Notes

-The bitshift expression shifts here a 1 sixteen times on the left, yielding 2 16 as required.

-The keyword function introduces the definition of a function. Here the fracpart function yields in the return value named y the fractional part of its argument x, and is used to perform a round-robin in the [0, 1) interval (closed at 0 and open at 1).

-The intrinsic function uint16 returns an unsigned 16-bit integer that approximates its floating point argument, here phase. This truncation of the floating point phase values provides the integer indexes needed to access the wave table in read mode.

MUSIC LANGUAGES

In some loose sense, all music-specific programming languages use, in one way or another, synchronous idioms, since they have to deal with temporal streams of audio samples. We decided to adopt here a somewhat historical order to present key music programming languages:

-Csound is, in a way, the father of modern audio synthesis languages [START_REF] Vercoe | Csound: a manual for the audio processing system and supporting programs with tutorials[END_REF][START_REF] Boulanger | The Csound Book[END_REF]]; -SuperCollider adopts an object-oriented programming approach, inspired by the SmallTalk language [McCartney 1996]; -Pure Data is, like Max/MSP [START_REF] Puckette | Max at seventeen[END_REF]], a typical representative of the visual programming paradigm often adopted by the computer music community, thanks to its appeal to the contemporary music composers [START_REF] Bresson | Visual Lisp/CLOS programming in OpenMusic[END_REF]]; -ChucK exemplifies the importance of on-the-fly programming that now can occur even during music performance through "live coding" practices [START_REF] Wang | ChucK: A Concurrent, On-the-fly Audio Programming Language[END_REF]]; -finally, Faust promotes the functional paradigm onto a block-diagram algebra, striving to balance expressivity and run-time performance [START_REF] Orlarey | An Algebra for Block Diagram Languages[END_REF]2009].

Csound

Presentation. The following position statement is extracted from the Csound official site, http://www.csounds.com.

Csound is a sound design, music synthesis and signal processing system, providing facilities for composition and performance over a wide range of platforms. It is not restricted to any style of music, having been used for many years in the creation of classical, pop, techno, ambient, experimental, and (of course) computer music, as well as music for film and television.

Oscillator. The Csound implementation osc.csd of the oscillator can be found below. We tested Csound version 5.11

¦ ¥

Design Notes

-Csound is the oldest musical language of this study: it is a C-based audio DSL following Music11, also developed by Barry Vercoe at MIT in the 1970s, and the MUSIC-N languages initiated by Max Mathews at the Bell Labs in the 1960s. Several aspects present in the Csound language (possibly inherited from previous languages) still persist in later musical languages, so we detail here several aspects of Csound that will be of use for the understanding of most of the sections dedicated here to musical languages.

-In the header, the two assignments "sr = 44100" and "kr = 441" stand for sample rate and control rate, which are two fundamental concepts in computer music. The first one specifies the discrete audio sampling rate, set according to the Nyquist frequency, which is twice the 20,000 Hz upper human listening bound needed at sampling time to avoid aliasing. The second one specifies the "control" rate; to save computing resources, it is usually set to a value smaller than the audio rate, since it is mostly used to manage music control information, which do not require the very high temporal resolution requested by sound signals.

-The Csound code of osc.csd presented here gathers into one file both the socalled orchestra and score parts, using XML-like sections, although Csound code had originally been stored in two distinct '.orc' and '.sco' files. "An orchestra is really a computer program that can produce sound, while a score is a body of data which that program can react to." [START_REF] Vercoe | Csound: a manual for the audio processing system and supporting programs with tutorials[END_REF]]. Beside the score, other means of launching the instruments exist, such as via MIDI9 or real-time events (see Section 6.5).

-The Csound syntax makes intensive use of one-letter prefixes:

-in an instrument definition, "a" and "k" specify signal rates (so that "aosc" is an audio-rate oscillator signal); -in an instrument definition, "p" followed by a number specifies a reference to the corresponding parameter field in the score part (here p4 corresponds to 20000 and p5 to 440 when used in i1, see below); -in the score part, "f" followed by a list of numbers declares a function table (here, the table f1 will be computed at 0 second, on 65536 points, using the unit generator 10, with a relative energy of 1 for the fundamental frequency; see next notes); -in the score part, "i" followed by a list declares a Csound note that references an instrument to be played (here i1 requests the computation of instr 1, from time 0, during 2 seconds, with an amplitude of 20000, at a frequency of 440 Hz); -finally, e asks for the execution of the score.

-The oscillator is synthesized by instr 1 in the orchestra part, using the oscil generator, which is a simple direct synthesis oscillator without interpolation. This generator has three arguments: its amplitude p4, its frequency p5 and its function table number 1, which refers to f1 in the score part; this latter function table relies on the tenth unit generator called "GEN10", specified as the fourth argument of f1.

-As GEN10 is also used in several musical languages in the next sections, we cite here its extensive description from the Canonical Csound Reference Manual [START_REF] Vercoe | The Canonical Csound Reference Manual[END_REF]]: GEN10 -Generate composite waveforms made up of weighted sums of simple sinusoids. Description: These subroutines generate composite waveforms made up of weighted sums of simple sinusoids. The specification of each contributing partial requires 1 pfield using GEN10. Syntax: f# time size 10 str1 str2 str3 str4 ... Initialization: size -number of points in the table. Must be a power of 2 or power-of-2 plus 1. str1, str2, str3, etc. -relative strengths of the fixed harmonic partial numbers 1, 2, 3, etc., beginning in p5. Partials not required should be given a strength of zero. Note: These subroutines generate stored functions as sums of sinusoids of different frequencies. The two major restrictions on GEN10, namely that the partials have to be harmonic and in phase, do not apply to GEN09 or GEN19. In each case the composite wave, once drawn, is then rescaled to unity if p4 was positive. A negative p4 will cause rescaling to be skipped.

SuperCollider

Presentation. The following position statement is extracted from the SourceForge http://supercollider.sourceforge.net site, since the SuperCollider official site, http://www. audiosynth.com, seems to be less well maintained.

SuperCollider is an environment and programming language for real-time audio synthesis and algorithmic composition. It provides an interpreted object-oriented language which functions as a network client to a state of the art, real-time sound synthesis server.

SuperCollider was written by James McCartney over a period of many years, and is now an open source (GPL) project maintained and developed by various people. It is used by musicians, scientists, and artists working with sound.

Oscillator. The SuperCollider implementation osc.scd of the oscillator can be found below. We tested SuperCollider version 3.4, rev 10205. The osc execution result is an infinite sample stream, output on the default SuperCollider audio port. et al. 2007]), such an oscillator could have been achieved in at least four different ways:

(1) the one presented here, using a Buffer filled by a sine1 pattern and played by a non-interpolating OscN wavetable oscillator;

(2) replacing OscN by an interpolating Osc wavetable oscillator;

(3) using BufRd, BufWr and SinOsc (since BufRd is to be filled by a unit generator); (4) using directly SinOsc.

-Since Version 3, SuperCollider is build upon a client/server architecture (communicating via OSC10 ), with a synthesis application on the server side and a remote language application on the client side. So here the free method allows the client to tell the server to free the memory of the buffer previously used.

-The first level of parenthesis surrounding the main block of code is a syntactic trick that is used to ensure that the enclosed lines of code will be launched at the same time by the SuperCollider interpreter; this occurs, in practice, when one simply double-clicks inside one of the parentheses (cf. [START_REF] Valle | The SuperCollider Help Book[END_REF]).

Pure Data

Presentation. The following statement is extracted from the Pd-FlossManual, available at http://en.flossmanuals.net/PureData. The Pure Data official site is http://puredata. info.

Pure Data (or Pd) is a real-time graphical programming environment for audio, video, and graphical processing. Pure Data is commonly used for live music performance, VeeJaying, sound effects, composition, audio analysis, interfacing with sensors, using cameras, controlling robots or even interacting with websites. Because all of these various media are handled as digital data within the program, many fascinating opportunities for cross-synthesis between them exist. Sound can be used to manipulate video, which could then be streamed over the internet to another computer which might analyze that video and use it to control a motor-driven installation. Programming with Pure Data is a unique interaction that is much closer to the experience of manipulating things in the physical world. The most basic unit of functionality is a box, and the program is formed by connecting these boxes together into diagrams that both represent the flow of data while actually performing the operations mapped out in the diagram. The program itself is always running, there is no separation between writing the program and running the program, and each action takes effect the moment it is completed.

Oscillator. The Pd implementation osc.pd of the oscillator can be found in Figure 2. We tested Pure Data version 0.42.5-extended-20091222. The osc execution result is an infinite sample stream, output on the default Pure Data audio port. -This patch is graphically separated into two main parts labelled PLAYER and INITIALIZATION; the graphical separation is materialized by an idiosyncratic line made up of a connection between two dummy bang objects. A bang object (a circle in a box) is used to trigger the most primitive of all event messages, in which only the information that a constant bang value has to be sent is encoded.

-Two trigger objects are used in order to enforce a sequential order of message emission (right-to-left order in Pure Data), which is crucial for such an event-driven language. The syntax of the trigger object includes a list of types, where the number of elements determines the number of outputs and where the type names (or oneletter type aliases) determine the type for the corresponding output, allowing type conversion. Here, the letters f and b stand respectively for types float and bang.

-For instance, the [trigger f f] object receives as input the value of 1 << 16, i.e., 2 16 . Proceeding right to left, it first initializes the local array myarray with the values of the first harmonic (specified by 1) of the sinesum function, predefined in Pure Data and having a semantics similar to GEN10's; the number of samples for one period is the value of the first argument $1, here 2 16 . Then, in a second step that exhausts its list of types, the trigger launches the command [send tablesize], which will be received by the PLAYER process11 .

-Object names ending with a "∼" (tilde) character denote signal objects, running at audio rate, and bold connections denote signal connections. "[Tilde objects] use continuous audio streams to intercommunicate, and also communicate with other ('control') Pd objects using messages." [START_REF] Puckette | The Theory and Technique of Electronic Music[END_REF] -To read our array myarray of sine samples, we use a phasor∼ object, which outputs a sawtooth signal between 0. and 1., here multiplied by the table size for table lookup to yield the successive indices. The dummy argument 0 allows phasor∼ to receive a non-signal message for the frequency (at control rate).

-The dac∼ object, for digital-to-analog converter, transfers the real-time audio outputs of Pure Data patches to the audio driver of the underlying operating system.

ChucK

Presentation. The following position statement is a mix of texts from the official site http://chuck.cs.princeton.edu and the ChucK manual.

ChucK is a new (and developing) audio programming language for real-time synthesis, composition, performance, and now, analysis. ChucK presents a new time-based, concurrent programming model that's highly precise and expressive (we call this strongly-timed), as well as dynamic control rates, and the ability to add and modify code on-the-fly. In addition, ChucK supports MIDI, OSC, HID, and multi-channel audio. It's fun and easy to learn, and offers composers, researchers, and performers a powerful programming tool for building and experimenting with complex audio synthesis/analysis programs, and real-time interactive control.

Oscillator. The ChucK implementation osc.ck of the oscillator can be found below. We tested ChucK version 1.2.1.3 (dracula). The osc execution result is an infinite sample stream, output on the default ChucK audio port. -The ChucK language is specifically designed to allow on-the-fly audio programming [START_REF] Wang | ChucK: A Concurrent, On-the-fly Audio Programming Language[END_REF]].

-The heart of ChucK's syntax is based around the massively overloaded ChucK operator, written as '=>'. "[This operator] originates from the slang term 'chuck', meaning to throw an entity into or at another entity. The language uses this notion to help express sequential operations and data flow" [START_REF] Wang | ChucK: A Concurrent, On-the-fly Audio Programming Language[END_REF]]. The ChucK operator's behavior relies on the strong typing system of this imperative language, depending on the type of both its left and right arguments.

-Several elements of ChucK, such as Gen10 (cf. Csound section), Phasor or dac (cf. Pure Data section), are inspired by features existing in previous musical languages.

-Here, the drive phasor is declared and piped to the g10 generator, itself connected to the digital-to-audio converter.

-Like in Csound, Gen10 has to be fed with a list of relative coefficients specifying the harmonics of the spectra; here a single-element array [1.] yields a single sinusoid.

-The infinite time loop allows the computing and playing processes declared above it to run; the loop body merely advances time by the arbitrary duration of 500::ms. Note that the timing model mandates the attachment of a time unit to each duration, such as milliseconds in "500::ms".

-Modifying the special variable now has the effect of advancing time, suspending the current process until the desired time is reached, and providing the other processes and audio synthesis engine with the computing resources needed to run in parallel.

-The value of now, which holds the current time, only changes when it is explicitly modified [START_REF] Wang | The ChucK Manual 1[END_REF]. "The amount of time advancement is the control rate in ChucK." [START_REF] Wang | ChucK: A Concurrent, On-the-fly Audio Programming Language[END_REF]

Faust

Presentation. The following position statement is extracted from the Faust official site, http://faust.grame.fr.

FAUST is a compiled language for real-time audio signal processing. The name FAUST stands for Functional AUdio STream. Its programming model combines two approaches: functional programming and block diagram composition. You can think of FAUST as a structured block diagram language with a textual syntax. FAUST is intended for developers who need to develop efficient C/C++ audio plugins for existing systems or full standalone audio applications. Thanks to some specific compilation techniques and powerful optimizations, the C++ code generated by the Faust compiler is usually very fast. It can generally compete with (and sometimes outperform) hand-written C code. Programming with FAUST is somehow like working with electronic circuits and signals. A FAUST program is a list of definitions that defines a signal processor block-diagram: a piece of code that produces output signals according to its input signals (and maybe some user interface parameters).

Oscillator. The Faust implementation osc.dsp of the oscillator can be found below. We tested Faust version 0.9.13. The osc execution result is an infinite sample stream, output as the process output signal, linked to the standard audio port via Jack12 . § ¤ = f r e q / f l o a t ( s a m p l i n g f r e q ) : (+ : f r a c p a r t ) ~_ : * ( f l o a t ( t a b l e s i z e ) ) ; osc ( f r e q )

= r d t a b l e ( t a b l e s i z e , sinwaveform , i n t ( phase ( f r e q ) ) ) ; process = osc ( 4 4 0 ) ;

¦ ¥

Design Notes

-The Faust language combines a block-diagram algebra [START_REF] Orlarey | An Algebra for Block Diagram Languages[END_REF]] with a functional paradigm [START_REF] Orlarey | Syntactical and Semantical Aspects of Faust[END_REF]].

-The keyword process is analogous to main in C and has to be defined [START_REF] Orlarey | Syntactical and Semantical Aspects of Faust[END_REF]].

-The sample rate constant SR is defined in the imported library file math.lib as a foreign constant, which is linked to the actual sampling rate of the host application through the architecture compilation mechanism of Faust and determined at initialization time [START_REF] Smith | Audio Signal Processing in Faust[END_REF]. This typical DSL feature protects against incompatibilities.

-Faust uses five block-diagram composition operators [START_REF] Orlarey | Syntactical and Semantical Aspects of Faust[END_REF]]: sequential composition A:B, parallel composition A,B, recursive composition A∼B, split composition A<:B and merge composition A:>B (the last two are not used here).

-The time processor definition "time = (+(1) ~_) , 1 : -;" uses the three essential block-diagram composition operators plus two more key elements. From right to left, there are: -the sequential composition operator ":", to connect the two inputs of the "-" processor with the output signals of the preceding processors to compute differences; -the parallel composition operator ",", to combine the two parallel processors that feed the "-" processor (note that order matters for the subtraction); -the recursive composition operator "∼", to specify a one-sample feedback increment that generates a series of natural numbers, starting at 1 (Figure 3 shows the blockdiagram schema of the time processor, where the small square on the output denotes the implicit sample delaying operation); -the identity block "_", used here in the one-sample recursive loop to directly connect the output to the input of the increment processor, with no other processor than the identity one; -the partial application "+(1)", using the curried form of the processor "+" to fix one of its arguments with the "1" value. -Integer operations are defined modulo the (implementation-dependent) machine integer size, so the increment operation above never overflows, but simply performs a round-robin on its domain.

-Infix notation is allowed in Faust as syntactic sugar, as in the fracpart definition where "x -floor(x)" is equivalent to "x, floor(x) : -".

-The read-only table rdtable stores values from a stream at initialization time. The data will then be accessed during execution. Its three parameters are the size of the table, the initialization stream, and the read-index signal [START_REF] Gaudrain | A Faust Tutorial[END_REF]].

-Faust default output is the audio system within which a Faust process is run.

SYNCHRONOUS LANGUAGES

There are various ways to introduce synchronicity in general-purpose programming languages. We focus, in this section, on our oscillator use case example to survey the usual approaches described in the literature:

-the direct approach, taken by Signal, Lustre and Esterel, is to make the notion of synchronous computation at the core of the language design per se; -a more indirect route is to add the notion of streams to an existing language, and among the multiple existing proposals we decided to present two such integrations as illustration: Lucid Synchrone, for the functional paradigm, over OCaml, and OpenMP Stream Extension, for the imperative one, over C and OpenMP.

Signal

Presentation. The following position statement is extracted from the Signal official site, http://www.irisa.fr/espresso/Polychrony.

Signal is based on synchronized data-flow (flows + synchronization): a process is a set of equations on elementary flows describing both data and control. The Signal formal model provides the capability to describe systems with several clocks (polychronous systems) as relational specifications. Relations are useful as partial specifications and as specifications of non-deterministic devices (for instance a non-deterministic bus) or external processes (for instance an unsafe car driver). Using Signal allows to specify an application, to design an architecture, to refine detailed components down to RTOS13 or hardware description. The Signal model supports a design methodology which goes from specification to implementation, from abstraction to concretization, from synchrony to asynchrony.

Oscillator. The Signal implementation OSC.SIG of the oscillator can be found below. We tested Signal version V4.16. The osc execution result is an infinite sample stream, output on the output signal; additional helper files, in particular clock files specifying explicit time ticks (not shown here), are needed to generate a user-specified output file of 200 samples. § ¤

process osc = ( ? event i n p u t C l o c k ; ! d r e a l o u t p u t ; ) ( | o u t p u t ^= i n p u t C l o c k
| o u t p u t : = r d t a b l e ( i n t e g e r ( phase ( f r e q ) ) ) | ) where c o n s t a n t d r e a l f r e q = 4 4 0 . 0 ; c o n s t a n t i n t e g e r s a m p l i n g f r e q = 44100; c o n s t a n t i n t e g e r t a b l e s i z e = 2 * * 16; -Arrays, such as sinwaveform of tablesize elements, are defined by intension, at initialisation time, using implicit quantification over indices such as i here.

-Data equations are functional, and the $ postfix is used to reference the previous item in a stream, while init is used to specify the initial value.

-The execution of osc relies upon the local rdtable process, parametrized with the appropriate frequency, to define its output signal. The rdtable process, in turn, outputs, for each integer in its tableindex input signal, the corresponding value of the sinwaveform table, initialized once and for all with a sampled sine function.

-Signal allows the use of simple processes called functions, such as the straightforward fracpart definition here, to help modularize Signal specifications.

Lustre

Presentation. The site http://www-verimag.imag.fr/The-Lustre-Toolbox.html is Lustre official repository and the following position statement is extracted from Wikipedia14 .

Lustre is a formally defined, declarative, and synchronous dataflow programming language, for programming reactive systems. It began as a research project in the early 1980s. In 1993, it progressed to practical, indus-trial use, in a commercial product, as the core language of the industrial environment SCADE, developed by Esterel Technologies. It is now used for critical control software in aircraft, helicopters, and nuclear power plants.

Oscillator. The Lustre implementation osc.lus of the oscillator can be found below. We tested Lustre version V4. The osc expected result is an infinite sample stream, output on the Y signal of the osc node. § ¤ -In a stream definition, pre is used to denote the previous value in the argument stream, while the arrow -> operator ("followed-by") is used to distinguish the initial value from the recursive expression when defining a stream by induction.

-Streams are typed, and ^is used to introduce aggregate vector types (its second argument is the vector size).

-The definition of the array t in time is by induction over array slices: t[0] is 0, while, for all i in [1..n-1], t[i] is t[i-1]+1, since 1^(n-1) is an array of n-1 elements, all initialized to 1.

-Array timeTab is initialized via time, when the whole program is loaded; its elements are integers from 0 to tablesize -1, numbering all samples in one sine period.

-The execution of osc, with a frequency argument as input, yields a stream based on the node rdtable. The phase node returns, for the same frequency, the recursively defined stream index, which is the succession of indices used to access, via rdtable, the sinwaveform array, also defined at load time.

-The const keyword flags identifiers denoting constant values. This is used here to compute the sinwaveform array.

-The Lustre version we used is in fact unable to manage dynamic access to arrays but only handles constant indexes, yielding a naming convenience for numbered constants like a[1], a[2] and so on, while this dynamic access feature with variable index reading support is clearly required to implement variable frequencies in osc (see Sec. 6.4). Newer, non open-source versions of Lustre, such as Lustre V6, do provide dynamic arrays.

Esterel

Presentation. The following position statement is taken from the original Esterel site, http://www-sop.inria.fr/meije/esterel/esterel-eng.html.

Esterel is both a programming language, dedicated to programming reactive systems, and a compiler which translates Esterel programs into finite-state machines. It is one of a family of synchronous languages, like SyncCharts, Lustre, Argos or Signal, which are particularly well-suited to programming reactive systems, including real-time systems and control automata. The Esterel v5 compiler can be used to generate a software or hardware implementation of a reactive program. It can generate C-code to be embedded as a reactive kernel in a larger program that handles the interface and data manipulations. It can also generate hardware in the form of netlists of gates, which can then be embedded in a larger system. Extensive optimization is available. We provide a graphical symbolic debugger for Esterel. We also provide support for explicit or BDD-based verification tools that perform either bisimulation reduction or safety property checking.

Esterel is now experimentally used by several companies and taught in several universities.

Oscillator. The Esterel implementation Osc.strl of the oscillator can be found below (see Design Notes also). We tested version v5 (and GCC 4.2.1 for the C files handling array accesses). The osc execution result is an infinite sample stream, output on the default Esterel output port. § ¤ -Esterel modules specify signals and signal computations that operate on the occurrence of events, including ticks issued by a logical clock.

-Esterel supports both internal or external signals. For instance, Osc defines internal signals index, phase (via Module Phase) and sample (via Module RdTable). As for external signals, frequency values appear on I while audio samples are output on O.

Synchronous Programming In Audio Processing: A Lookup Table Oscillator Case Study

A:23 -Esterel signal computations emit values of interest on outputs from values read on inputs, using the ?I notation. All computations are assumed to be performed at each tick in zero time.

-The keyword every is syntactic sugar for an event-controlled looping statement. For instance, each time a new frequency value appears on I in Osc, Module Phase is run in a separate thread, with appropriate bindings for input freq and output phi, to get the proper sequences of array indices in the phase signal while an infinite loop thread emits on O the samples obtained via the RdTable module, using the index and phase signals.

-Phase illustrates another aspect of Esterel, namely the concept of variables storing values. Here, the index variable takes, at each time tick, the successive values of the sample indices, while preindex keeps track of the previous value15 . The successive indices of the samples in the sine wavetable appropriate for yielding a sine of the given frequency freq are emitted on the phi signal. The internal step signal is used to broadcast the sample index increment.

immediate keyword indicates that the corresponding code is evaluated immediately, even when the tick is already present, as is the case when the program starts.

Lucid Synchrone

Presentation . The following position statement is taken from the official Lucid Synchrone site, http://www.di.ens.fr/~pouzet/lucid-synchrone.

Lucid Synchrone is an experimental language for the implementation of reactive systems. It is based on the synchronous model of time as provided by Lustre combined with some features from ML languages. The main characteristics of the language are the following: -It is a strongly typed, higher-order functional language managing infinite sequences or streams as primitive values. These streams are used for representing input and output signals of reactive systems and are combined through the use of synchronous data-flow primitives à la Lustre.

-The language is founded on several type systems (e.g., type and clock inference, causality and initialization analysis) which statically guarantee safety properties on the generated code... -The language is built above Objective Caml used as the host language. Combinatorial values are imported from Objective Caml and programs are compiled into Objective Caml code. A simple module system is provided for importing values from the host language or from other synchronous modules.

-It allows to combine data-flow equations with complex state machines (Mealy and Moore machines with various forms of transitions). This allows to describe mixed systems or Mode-automata as originally introduced by Maraninchi & Rémond.

-Data-types (product types, record types and sum types) can be defined and accessed through pattern matching constructions.

Oscillator. The Lucid Synchrone implementation osc.ls of the oscillator can be found below. We tested Version 3.0b. The osc execution result is an infinite sample stream, output on the default Lucid Synchrone output port. § ¤ l e t s t a t i c t a b l e s i z e = 65536 l e t s t a t i c s a m p l i n g f r e q = 44100 l e t s t a t i c t w o p i = 6.28318530717958623 l e t f t a b l e s i z e = f l o a t _ o f _ i n t t a b l e s i z e l e t s t a t i c sinwaveform = Array . make t a b l e s i z e 0 . 0 l e t s t a t i c gen_sin ( ) = l e t rec feed i = match i with | 0 -> ( ) | i -> ( Array . s e t sinwaveform ( i -1) ( s i n ( ( f l o a t _ o f _ i n t ( i -1) ) * . t w o p i / . f t a b l e s i z e ) ) ; feed ( i -1) ) end i n feed t a b l e s i z e l e t s t a t i c s i d e f e e d i n g = gen_sin ( ) l e t f r a c p a r t x = x -. f l o o r ( x ) l e t node phase f r e q = l e t rec i n d e x = 0 . 0 -> f r a c p a r t ( ( f r e q / . ( f l o a t _ o f _ i n t s a m p l i n g f r e q ) ) + . pre ( i n d e x ) ) i n i n t _ o f _ f l o a t ( f t a b l e s i z e * . i n d e x ) l e t r d t a b l e t a b l e i n d e x = Array . g e t sinwaveform t a b l e i n d e x l e t node osc f r e q = r d t a b l e ( phase ( f r e q ) ) ¦ ¥

Design Notes

-Lucid Synchrone imports most of its value and typing constructs from Objective Caml (OCaml), a mostly-functional object-oriented language in which (possibly recursive) functions are first-class values [START_REF] Leroy | The Objective Caml system release 3.12 Documentation and user's manual[END_REF]. It is also inspired by Lustre signal processing concepts.

-Following Lustre, Lucid Synchrone adds to OCaml the notion of a node, defined via let node declarations. These nodes are used to manipulate streams, which are infinite sequences of values linked to a particular clock.

-In a stream definition i -> s, i denotes the default, first value of the stream while s is the inductive definition of a stream element. A reference to the previous stream value is allowed using the pre operator.

-Array is an OCaml module, used here within Lucid Synchrone, that provides standard operations to define (make) or manipulate (set and get) array elements.

-In OCaml, integer operators use the traditional syntax (such as * for multiplication), while floating-point constructs use a different notation, via the addition of a dot (".") suffix to the integer notation.

-The execution of the osc node, given a frequency freq argument, yields a stream based on the implicit mapping of the rdtable function to the stream phase(freq). As in Lustre, the phase node defines the local stream index, later used to iteratively access the sinwaveform array.

-Lucid Synchrone allows the definition of constants via the let static binding; it is used here to populate, in a simple recursive manner via gen_sin, the constant array sinwaveform.

OpenMP Stream Extension

Presentation. The OpenMP Stream Extension comes as a GCC CVS branch, at http: //gcc.gnu.org/viewcvs/branches/omp-stream. Below follows its position statement.

The stream-computing extension to OpenMP enables the expression of flow dependences between OpenMP tasks. This allows to statically specify the program's dynamic task graph, where tasks are connected through streams that transparently privatize the data. The programming model is conducive to making relevant data-flow explicit and to structuring programs in ways that allow simultaneously exploiting pipeline, data and task parallelism. Stream computations help reduce the severity of the memory wall in two complementary ways: (1) decoupled producer/consumer pipelines naturally hide memory latency; and (2) they favor local, on-chip communications, bypassing global memory. This extension provides dataflow semantics close to Kahn process networks and guarantees functional determinism, a major asset in the productivity race. In contrast with common streaming frameworks, the communication patterns can be dynamic, while preserving the determinism of arbitrarily merging and splitting data streams. The GCC prototype implementation of the OpenMP extension for stream-computing has been shown to be efficient to exploit mixed pipeline-and data-parallelism, even in dynamic task graphs [START_REF] Pop | A Stream-Computing Extension to OpenMP[END_REF]. It relies on compiler and runtime optimizations to improve cache locality and relies on a highly efficient lock-free and atomic operation-free synchronization algorithm for streams.

We need to emphasize here that the OpenMP Stream Extension is particularly interesting for our survey since, built on top of an imperative language (C) extended with asynchronous parallel constructs (OpenMP), this language extension is not strictly synchronous. Yet it offers to programmers the ability to perform parallel signal processing operations that loosely adhere to the synchronous hypothesis. Indeed, all stream operations are specified to be deterministic and to not require explicit synchronization actions. This illustrates how synchronous-like operations could be added to other existing traditional languages.

Oscillator. The OpenMP Stream Extension [START_REF] Pop | Leveraging Streaming for Deterministic Parallelization : an Integrated Language, Compiler and Runtime Approach[END_REF]] implementation osc.c of the oscillator can be found below. We tested a prototype directly with its author, Antoniu #pragma omp p a r a l l e l num_threads ( 2 ) d e f a u l t ( none ) shared ( t a b l e s i z e , sinwaveform , s a m p l i n g f r e q ) { #pragma omp s i n g l e { f l o a t f _ s f _ r a t i o , index , phase ; f l o a t f r a c _ a d d = 0 . 0 ; i n t i = 0 ; while ( i ++ < o u t p u t s i z e ) { #pragma omp task shared ( s a m p l i n g f r e q ) o u t p u t ( f _ s f _ r a t i o ) num_threads ( 2 ) { f _ s f _ r a t i o = ( ( f l o a t ) f r e q ) / ( ( f l o a t ) s a m p l i n g f r e q ) ; } #pragma omp task i n p u t ( f _ s f _ r a t -OpenMP Stream Extension is an upward-compatible extension of the OpenMP standard [START_REF] Dagum | OpenMP: an industry standard API for shared-memory programming[END_REF], which extends sequential languages with options for parallel execution. OpenMP has multiple language bindings, and its C variant uses #pragma omp C preprocessor-like directives to describe thread-parallel tasking.

-The parallel pragma is an OpenMP-specific directive used to open a parallel section in which multiple tasks may be used on up to num_threads parallel threads. A separate task is launched for each omp task pragma, running the statement following it in parallel on one of these threads. The single pragma enforces its following sequence of code to be run by only one thread (which runs here the while loop that starts all required tasks).

-All variables declared within a parallel block are local to each task by default; global variables accessed by a particular parallel construct have to be listed in the shared parameter.

-OpenMP Stream Extension extends the task pragma, used to specify an OpenMP parallel task, with the input and output parameters that introduce stream processing into OpenMP. Variables such as index and phase are promoted to streams; memory is allocated and managed automatically by the OpenMP Stream Extension runtime in a pipeline fashion, hiding to the programmer the implementation details. The input/output arguments can be seen as queues on which the pipeline stages, implemented as separate parallel tasks, synchronize and exchange signal data.

-A stream parallel task such as the one defining phase (see commented line) processes its input signals to yield output data accordingly.

DISCUSSION

We look, in this section, at some of the issues raised by our implementations of osc.

In particular, we discuss (1) the differences between DSL and general-purpose languages, (2) the subtle differences in the notions of time and signals these formalisms introduce, (3) how the synchronous hypothesis affects language design, (4) the way these languages handle aggregate data structures such as arrays, and finally ( 5) the integration of asynchrony.

The DSL vs. General-Purpose Languages Debate

In this work, we surveyed 10 languages, 5 specific to computer music applications and 5 general synchronous languages. Each of these languages provides in one way or another answers to the same design questions, such as how to manage time or what are signals supposed to represent for the problems at hand. Yet, the final language design decisions, summarized in Table IV, vary widely, mostly along the line of whether the corresponding language is intended to be used in a somewhat limited application domain, i.e., strives to be a music-specific DSL, or able to tackle a wide range of timeconstrained problems, i.e., is a general-purpose synchronous language. Of course, the DSL vs. General-Purpose separation line is not enough to automatically imply which particular programming traits a given language should adopt. To get a feel for the spectrum of notions spanned by this survey, we summarize in Table V the main features of these programming tools: (1) their core computing paradigm, (2) the way they specify, in particular for recursive definitions, the memory values at previous time slots, via delays and initializations, and (3) their design approach of parallelism specification at the most abstract level, thus not taking in account any hardware constraints. One obvious result of our work is that using a single simple yet significant application to illustrate the expressiveness power of various programming languages provides an interesting and practical point of view for software development tool selection. In particular, choosing an audio application as our main running test case yields a specific example of the intrinsic value of Domain Specific Languages as a general and practical approach to the software productivity wall [START_REF] Mernik | When and how to develop domain-specific languages[END_REF][START_REF] Van Deursen | Domain-specific languages: An annotated bibliography[END_REF]]. Indeed and not surprisingly, we were able to use all these tools to get the work done, except for a technical limitation of the open-source version of Lustre we used. Yet, and as anyone could have expected, all programs using music-focused DSLs are much shorter, and also readable, than the ones based on general-purpose synchronous languages.

A positive by-product of the conciseness of DSL-based programs is that they are consequently probably more often correct than those based on the other formalisms. Indeed, even though the idea that the number of bugs introduced in a particular program is mainly a function of the number of lines of code and is rather independent of the programming language used may be mostly folklore, we feel that our analysis illustrates in a very concrete manner that conciseness, and hopefully then lack of software defects, clearly lies within the field of DSLs.

Logical and Physical Times

Although time is, as we mentioned in Section 2, the core concept that structures the definition of all the languages used in this use case study, it is obvious that musicoriented and reactive systems have a somewhat different view of what this notion means. In the traditional synchronous programming world, time is mostly a logical notion, around which computations are scheduled; indeed, multiple clocks can even be defined, e.g., via the ^= symbol in Signal. For music aficionados, time is a hardware, physical notion deeply linked to the speed at which sound is sampled by input and output converters; the key notion here is the "sampling rate", e.g., via the SR predefined identifier in Faust. In some sense, music languages, as DSLs, are more closely linked to the practical matters at hand than the more abstract, hence more general, traditional synchronous programming languages.

Consequently, the notion of what a signal is varies also in the two communities, even though both use the same foundation, i.e., the concept of time. Following a more pragmatic approach, music synchronous languages view signals as mappings from regularly-spaced, sampling rate-sequenced time ticks to values. Traditional languages have to deal with more complex clocks, for instance where time events might even be absent, which leads to more abstract notions of signals. In music applications, all values of a sampled signal are defined (barring computing errors such as a 1/0 division), while general signals may yield undefined values for some time events, and such undefined values are first-class in these languages [START_REF] Benveniste | The synchronous languages twelve years later[END_REF]].

The apparently limited approach of what time and signals must be in music applications is mitigated by the fact that there is a strong tendency in this community to address timing issues as a two-tiered problem. First, a low-level synchronous layer, synchronized to the audio rate, deals with concrete and predictive sampled signals. Then, a higher-level control layer, in fact mostly asynchronous (Csound being a notable exception, using the ksmps variable we discuss in Section 6.3), schedules the low-level activities in response to the user. These two strata are often embedded in the same language or environment, using one scheduler at audio rate (typically 44,100 Hz, with high priority and low latency based on buffering techniques) and another one at a much lower "control rate", usually managing MIDI events (medium priority and latency) and GUI objects (low priority and high latency). On the other hand, traditional synchronous languages tend to address only the issues relevant to the first class of problems, using either a sample-driven execution scheme as in Lustre or an eventdriven one as in Signal, and rely on a different programming paradigm to link the synchronous modules together, possibly using a GALS16 approach [START_REF] Teehan | A survey and taxonomy of GALS design styles[END_REF]]. Thus, they usually require more general and flexible notions for time and signals than the ones found in audio languages, since they do not have to follow the fundamental rhythm of the otherwise primary audio sampling rate.

The Synchronous Hypothesis in Computer Music

Synchronous languages, because of their more abstract and logical view of time and signals, are formally defined through complex mathematical semantic models [START_REF] Manna | Temporal verification of reactive systems: safety[END_REF][START_REF] Schneider | Verification of reactive systems: formal methods and algorithms[END_REF]]. These formal specifications are moreover of key importance given the domains these languages target, i.e., within strongly reactive and very often mission-critical environments. Music, on the other hand, can, and has to, deal with more "soft" constraints: the notion of truth is more in the ear of the listener/composer than in the strict structure of a mathematical proof. Of course, the human ear is quite a subtle device, and professional listeners have been shown to be quite sensitive to even very small differences in two audio signals; even one missing sample may induce a dramatic sound artefact that any listener will hear. Moreover, even for music applications, a trend is appearing, which calls for more assurance in the fidelity of the audio processing methods, in particular when one wishes to address the issue of long-term and exact preservation of the world musical heritage [START_REF] Guercio | Authenticity issue in performing arts using live electronics[END_REF][START_REF] Bachimont | Preserving interactive digital music: a report on the MUSTICA research initiative[END_REF][START_REF] Barkati | Two Recent Extensions to the FAUST Compiler[END_REF].

These two approaches regarding this core notion of time in the synchronous layer lead to different approaches to the compilation process. Traditional synchronous languages are more specification-oriented than audio languages; the programmer provides equations defining clock and signal values, relying on the compiler to implement them in efficient sequences of computations. Audio/music frameworks have to deal less with the issue of reifying relationships between logically synchronized computations than with the efficient implementation of explicitly synchronized processes (see for instance Pure Data connected graphs or Faust functional expressions).

These two different ways of addressing the issue of correctness, i.e., the ability of performing a given set of computations under timing constraints, have had a significant impact on language design. Synchronous languages adopt the synchronous hypothesis, which mathematically ensures that all specifications will be met, both in the computation and time domains; no event will ever be lost. On the contrary, in the music realm, the synchronous hypothesis has never been a well-identified key design principle; audio samples may, in practice, be lost. To lower the number of such occurrences, music language designers have adopted a much more pragmatic approach: audio processing is not performed on a sample basis, but rather on buffers of multiple audio and control samples, thus lowering the I/O overhead associated to per-sample computations. This hands-on design decision is in fact visible in many music languages we surveyed above; for instance, our Csound example defines the variable ksmps, which specifies the number of elements to be used to size the control buffers used internally to process sound. Such low-level buffer management does not need to appear in synchronous languages. Note however that, as as consequence of this more "relaxed" approach to correctness handling, music languages have been sometimes explicitly equipped to deal with event loss; the outcomes of this research might, interestingly, be of use by the synchronous language community, having to handle hardware faults that may fall outside of the synchronous hypothesis protection.

Dynamic Array Management

Table lookup is about performance: computer music makes an intensive use of wavetables to avoid the expensive computation of trigonometric functions like sine functions for each sample at given audio rates, typically 44,100 times by second, for audio synthesis (wavetable synthesis, waveshaping, etc.). It is noticeable that most of the music programming languages studied here, except Faust, borrow the idea of the GEN routines introduced in Csound; they are used as data generators to fill so-called function tables [START_REF] Boulanger | The Csound Book[END_REF]]. For instance, our oscillator uses the GEN10 routine to fill the oscillator sample table at initialization time with a sum of sinusoids (only one here); this table is then read using a wrap-around lookup process. Faust provides support for load-time table initialization and reading operation via the rdtable ternary function.

Our study reveals that general-purpose synchronous languages are often poorly equipped to support tables. Of course, they cannot be expected to provide music-specific GEN-like routines, but, more surprisingly at first sight, most of them simply do not handle array data structures, as is the case with the Esterel and Lucid Synchrone languages in the versions we used. Furthermore, the Lustre version we tested do provide an array syntax, but only as syntactic sugar for variables numbering, not for dynamic array access. Of course, it is generally possible to handle array initialization and dynamic access by importing foreign functions, C functions in most languages, as we did in our Esterel implementation of the oscillator, or OCaml functions in Lucid Synchrone, as we showed. The underlying reason for not handling arrays in the languages themselves is often the difficulty of ensuring that the synchronous time and memory constraints are still enforced, which is crucial for critical synchronous applications.

Commercial and more recent versions of Lustre and Esterel do handle arrays. Nevertheless, our survey suggests that the designers of synchronous languages could look at the GEN-like mechanism inspired by music programming languages as a safe strategy for the introduction of array data structures in these formalisms. Another possible approach to ensure a mathematically-correct integration of arrays and synchronous constraints is to couple in a single analysis the rates of signals with the size of the elements they convey (see for instance [START_REF] Jouvelot | Dependent vector types for data structuring in multirate Faust[END_REF]).

Event Management

Our survey focused on the audio signal processing part of the computer music domain, since audio DSP shares obvious features with synchronous applications, among which time and signal concepts -even though these are subtly different in both fields, as we have shown. The DSP part corresponds to the sampled scheme of evaluation of synchronous languages, where the main loop handles each sample, as opposed to their control scheme, where the main loop manages each interaction event. Synchronous languages often rely on a two-tier strategy to handle the integration of asynchrony, for instance via a GALS approach; most computer music languages are, them, inherently hybrid along the synchronous/asynchronous separation line.

Indeed, in addition to the DSP part, most music programming languages also embed event management for the inherently asynchronous occurences of musical notes and interactive remote control of parameters. Asynchronous event management is usually handled using message passing standards such as MIDI or OSC with no time tags. It is typically implemented via fixed-size event FIFOs or dedicated schedulers that run at a lower priority than the DSP one: such implementations may lead to nondeterministic effects when overflows occur. Note that this approach can also be applied to user-induced asynchronous events such as I/O operations, as is the case for Super-Collider.

On the other hand, dealing with these asynchronous events can be performed by embedding them within a synchronous framework, as is done in Csound, Pure Data or ChucK. They are here synced on a clock running at a specific control rate, which is usually lower than the audio rate since these events occur less frequently than audio samples. This approach may lower the computing load but lead to a loss of precision or even data loss when events are issued at too fast a pace; such a behavior may occur, for instance, in SuperCollider, when events are synchronized on AppClock instead of SystemClock. Such a synchronous handling can also be used when dealing with more time-based events such as timeouts, which may also be synced to the audio or control rates.

A challenging idea suggested by our survey would be to study if and how musical programming languages could improve their event management processes by borrowing from the mathematically-well founded control handling of the sophisticated synchrony traits introduced by synchronous languages, and thus benefit from their formal consistency.

CONCLUSION

We performed a practical, use case-oriented survey of ten key music-specific and general-purpose synchronous programming languages, implementing in each of them a simple yet significant audio processing algorithm, namely a frequency-parameterized oscillator. We believe this survey provides the first bridge between two mature and widely successful computing fields, the more than 50-year old computer music domain and the 40-year old niche of synchronous programming languages. Our work showed that the wide variety of existing music and synchronous languages leads to a large spectrum of program sizes and styles, even for the simple case of the oscillator, which was our running example throughout the article.

Our application-oriented comparison work, and the discussion points it led to, can be of use to language designers interested in the relationships and opportunities for mutual interactions between synchronous and computer music language designs. Moreover, programmers will get from our survey a better feeling for what the two audio and synchronous families of programming languages have to offer, both in common and on their own, extending their views on how explicit timing issues can be dealt with at various levels of abstraction.

Our present work has focused on programming language design issues. It would be interesting to see whether our findings regarding DSLs' benefits can be leveraged to more complex use case applications. Future work needs also to address the implementation, performance, environment integration and event management aspects of such a comparison, since these factors are also key in the decisions leading to the choice of a particular language or language paradigm in software projects. Finally, the choice of our audio oscillator running example creates some bias in our comparison of generalpurpose and music-specific languages; this calls for an other, symmetric study, which would use a typical synchronous application, such as for instance ABRO [START_REF] Berry | The Esterel v5 Language Primer: Version v5_91[END_REF]], to provide a balanced assessment of both programming paradigms. their kind feedback, and the reviewers for their detailed comments and suggestions. The motivation for this study comes from the French ASTREE17 ANR 2008 CORD 003 01 research project, which addresses the preservation issues of synchronous programs in computer music, using the Faust real-time audio processing language as the core foundation for such preservation efforts.

Fig. 1 .

 1 Fig. 1. Truncated lookup table oscillator

(

  var t a b l e s i z e = 1 << 1 6 ; b = Buffer . a l l o c ( s , t a b l e s i z e , 1 ) ; / / a l l o c a t e a B u f f e r b . s i n e 1 ( 1 . 0 , true , f a l s e , t r u e ) ; / / f i l l t h e B u f f e r {OscN . a r ( b , 440 , 0 , 1 ) } . p l a y / / N : Non-i n t e r p o l a t i n g ) b . f r e e ; ¦ ¥ Design Notes -In SuperCollider [McCartney 1996], which has over 250 unit generators (cf. [Valle

Fig. 2 .

 2 Fig. 2. The osc.pd implementation in Pure Data.

  i v e => Gen10 g10 => dac ; / / gen10 s i n u s o i d a l lookup t a b l e [ 1 . ] => g10 . c o e f s ; / / l o a d up t h e p a r t i a l s a m p l i t u d e c o e f f s 440 => d r i v e . f r e q ; / / s e t f r e q u e n c y f o r r e a d i n g t h r o u g h t a b l e while ( t r u e ) / / i n f i n i t e t i m e l o o p { 5 0 0 : :ms => now ; / / advance t i m e } ¦ ¥ Design Notes

Fig. 3 .

 3 Fig. 3. Block-diagram schema of the time processor

-

  c o n s t a n t d r e a l t w o p i = 6.28318530717958623; process r d t a b l e = ( ? i n t e g e r t a b l e i n d e x ; ! d r e a l sample ; ) ( | sample : = sinwaveform [ t a b l e i n d e x ] | ) where c o n s t a n t [ t a b l e s i z e ] d r e a l sinwaveform = [ { i to ( t a b l e s i z e -1) } : s i n ( ( d r e a l ( i ) * t w o p i ) / d r e a l ( t a b l e s i z e ) ) ] ; end ; process phase = ( ? d r e a l f r e q ; ! d r e a l p h i ; ) ( | i n d e x : = f r a c p a r t ( ( f r e q / d r e a l ( s a m p l i n g f r e q ) ) + index$ ) | p h i : = d r e a l ( t a b l e s i z e ) * i n d e x | ) where d r e a l i n d e x i n i t 0 . 0 ; end ; function f r a c p a r t = ( ? d r e a l f r a c p a r t I n ; ! d r e a l f r a c p a r t O u t ; ) ( | f r a c p a r t O u t : = f r a c p a r t I n -f l o o r ( f r a c p a r t I n ) | ) ; end ; Signal processes manipulate signals, i.e., named streams of typed data, either as input "?" or output "!", here of floating point numbers in double precision dreal. Local subprocesses are defined similarly. -Process behavior is defined via sets of functional equations on signals between the (| and |) enclosing symbols; these equations constrain either the values in a given signal, via the := connector, or clocks, via the ^= connector, used here to impose that signals output and inputClock share the same timing information.

-

  i n t ) returns ( Y : r e a l ) ; l e t Y = s i n ( ( ( r e a l X ) * t w o p i ) / ( r e a l t a b l e s i z e ) ) ; t e l node f r a c p a r t ( X : r e a l ) returns ( Y : r e a l ) ; l e t Y = Xf l o o r ( X ) ; t e l node phase ( f r e q : r e a l ) returns ( Y : r e a l ) ; v a r i n d e x : r e a l ; l e t i n d e x = 0 . 0 -> f r a c p a r t ( ( f r e q / ( r e a l s a m p l i n g f r e q ) ) + pre ( i n d e x ) ) ; Y = ( r e a l t a b l e s i z e ) * i n d e x ; t e l node r d t a b l e ( t a b l e i n d e x : i n t ) returns ( Y : r e a l ) ; l e t Y = sinwaveform [ t a b l e i n d e x ] ; --Dynamic a r r a y access . t e lnode osc ( f r e q : r e a l ) returns ( Y : r e a l ) ; l e t Y = r d t a b l e ( i n t phase ( f r e q ) ) ; Lustre sees computation as the processing of data exchanged between nodes. Within each node, functional definitions of data streams are expressed as possibly recursive equations.

  s i g n a l s t e p : double i n emit s t e p ( ? f r e q / s a m p l i n g f r e q _ c t e ) ; var i n d e x : = 0 . 0 : double , p r e i n d e x : = 0 . 0 : double i n every immediate t i c k do emit p h i ( t a b l e S i z e _ c t e _ d b * p r e i n d e x ) ; i n d e x : = ? s t e p + p r e i n d e x ; p r e i n d e x : = i n d e xf l o o r _ d b ( i n d e x ) ; implementation of the oscillator relies on the Esterel Osc.strl module file provided above and C helper functions, not presented here, that handle arrays, a data structuring mechanism not provided by the public-domain version of Esterel we used. We wrote the following functions, declared as external C functions in Esterel modules via the function keyword: void init_sinwaveform(), that initializes a local C array with the double-formatted 65536 samples of a one-period sine function; double sinwaveform(int i), that returns the i-th value in this local sampled sine C array; double floor_db(double d) and int floor_int(double b), that return the floor value of d in either double or int format; -and, finally, int main(), that calls init_sinwaveform(), provides the initial frequency value of 440 Hz to the Esterel input I in the Osc module via a call to Osc_I_I(440.0) and then calls Osc() to initiate Esterel processing. These last two functions are generated by the Esterel compiler.

  Pop (from MINES ParisTech's Computer Science Research Center). The osc execution result is the printing on the standard output of the first 200 values of the expected sinusoid. § ¤ # include < s t d l i b . h> # include < s t d i o . h> # include <math . h> # define f r e q 440 # define o u t p u t s i z e 200 # define t w o p i 6.28318530717958623 s t a t i c i n l i n e f l o a t f r a c p a r t ( f l o a t x ) { r e t u r n xf l o o r ( x ) ; } i n t main ( i n t argc , char * * argv ) { i n t i ; i n t t a b l e s i z e = 1 << 1 6 ; i n t s a m p l i n g f r e q = 44100; f l o a t * sinwaveform = ( f l o a t * ) malloc ( t a b l e s i z e * s i z e o f ( f l o a t ) ) ; f o r ( i = 0 ; i < t a b l e s i z e ; ++ i ) sinwaveform [ i ] = s i n ( ( ( f l o a t ) i ) * t w o p i / ( ( f l o a t ) t a b l e s i z e ) ) ;

  i o ) o u t p u t ( i n d e x ) shared ( f r a c _ a d d ) { f r a c _ a d d = f r a c p a r t ( f r a c _ a d d + f _ s f _ r a t i o ) ; i n d e x = f r a c _ a d d ; } #pragma omp task shared ( t a b l e s i z e ) i n p u t ( i n d e x ) o u t p u t ( phase ) { phase = i n d e x * t a b l e s i z e ; / / A stream p r o c e s s o r } #pragma omp task shared ( sinwaveform ) i n p u t ( phase )shared ( s t d o u t ) { f p r i n t f ( s t d o u t , "%f \ t %f \ n " , sinwaveform [ ( i n t ) phase ] , phase ) ; }

Table I .

 I Selection of music and general-purpose synchronous languages

	Csound	MIT	B. Vercoe, J. Fitch et al.
	SuperCollider	Univ. Texas	J. McCartney et al.
	Pure Data	UCSD	M. Puckette
	ChucK	Princeton Univ.	G. Wang, P. Cook
	Faust	GRAME	Y. Orlarey et al.
	Signal	IRISA/INRIA	A. Benveniste, P. Le Guernic
	Lustre	CNRS/Verimag	P. Caspi, N. Halbwachs
	Lucid Synchrone	Verimag & Paris 11	P. Caspi, G. Hamon, M. Pouzet
	Esterel	MINES/INRIA	G. Berry et al.
	OpenMP Stream	MINES ParisTech	Antoniu Pop

Table II .

 II Oscillator signature: general constants and functions

	const tablesize = 65536	// number of sound samples
	const sinwaveform[tablesize]	// sampled sinusoid (one period)
	const samplingfreq = 44100	// audio sampling rate (Hz)
	const freq = 440	// 'A' diapason frequency (Hz)
	const twopi = 6.28318530717958623
	void osc(freq)	// main function
	float rdtable(table, index)	// dynamic table read access
	float phase(freq)	// phase for each tick
	float fracpart(x)	// fractional part of float x in [0,1)

  (float samples) Sep 24 2009, with the graphical interface QuteCsound version 0.4.4. The osc execution result is an infinite sample stream, output on the default Csound audio port.

	§				¤
	<CsoundSynthesizer>
	< CsInstruments >
	s r		=	44100
	k r		=	441
	ksmps		=	100
	n c h n l s		=	1
			i n s t r 1
	aosc		o s c i l	p4 , p5 , 1
			o u t	aosc
			endin
	< / CsInstruments >
	<CsScore>
	; use GEN10 t o compute a s i n e wave
	f 1	0	65536	10	1
	; i n s	s t r t	dur	amp	f r e q
	i 1	0	2	20000	440
	e
	< / CsScore>
	< / CsoundSynthesizer>

Table IV .

 IV Design concepts comparison summary

		Music programming languages	Synchronous languages
	Code size much shorter	longer
	Time	mostly a hardware notion	mostly a logical notion
	Signals	simple tick mappings	abstract and complex clocks
	Layers	low-level and interactive high-level synchronous layer GALS a
	a See Section 6.5 for GALS.

Table V .

 V Salient design points of surveyed languages

		Paradigm	Delay	Initialization Parallelism
	Csound	orchestra and score delay	2 nd arg.	orchestra
	SuperCollider	object-oriented	DelayN	3 rd arg.	implicit
	Pure Data	visual	delread∼	2 nd arg.	graph
	ChucK	on-the-fly	Delay	.delay	implicit
	Faust	functional	∼	0	, or par
	Signal	relational	signal$	init	implicit
	Lustre	equational	pre	->	implicit
	Esterel	imperative	pre(?signal) init	||
	Lucid Synchrone functional	pre	->	implicit
	OMP Stream	imperative	window	explicit	omp task

Table VI .

 VI Table support

		Initialization	Dynamic Access
	Csound	f1 0 65536 10 1 ; GEN10	oscil p4, p5, 1
	SuperCollider b.sine1	{OscN.ar(b,440,0,1)}.play
	Pure Data	sinesum $1 1	tabread∼ myarray
	ChucK	[1.] => g10.coefs	Gen10 g10 => dac
	Faust	rdtable 1 st and 2 nd arg.	rdtable 3 rd arg.
	Signal	[i to (size-1):sin(...)]	sinwaveform[tableindex]
	Lustre v4	external C code	imported function
	Lucid Sync.	OCaml Array.make and .set	OCaml Array.get
	Esterel v5	external C code	imported function
	OMP Stream	C code	C code

ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

Domain-Specific Language. ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

MUsic Simulator-Interpreter for COMpositional Procedures. ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

Association française pour la cybernétique économique et technique. ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

The original language is put in parenthesis.ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

Note that adapting this technique to generate a different waveform, and thus yield a different sound, amounts to simply changing the values stored in the vector of samples. This approach is, by the way, at the core of most current commercial wavetable-driven music synthesizers.

int corresponds to the floor function if its argument is positive, which is the case for phase, and otherwise to ceiling.ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

Octave is an open-source variant of Matlab: http://www.gnu.org/software/octave/.

http://www.mathworks.com. ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

Musical Instrument Digital Interface, an industrial protocol defined in 1983. ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

Open Sound Control, a content format for digital device communication defined at UC Berkeley CNMAT[START_REF] Wright | Open sound control: an enabling technology for musical networking[END_REF]].ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

send commands are, in fact, spurious, since they could replaced by graphical connections; they have been introduced in Pure Data to help programmers better visually structure their programs.ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

http://jackaudio.org ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

Real-Time Operating System. ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

http://en.wikipedia.org/wiki/Lustre_\%28programming_language\%29. ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

The pre operator on Esterel signals could have been used here too.ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

GALS stands for "Globally Asynchronous, Locally Synchronous".ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

ASTREE stands for "Analyse et synthèse de traitements temps réel", i.e., "Analysis and Synthesis of Real-Time Processes". ACM Computing Surveys, Vol. V, No. N, Article A, Publication date: YYYY.

ACKNOWLEDGMENT

The authors thank Daniel Gaffé, Léonard Gérard, Yann Orlarey, Cédric Pasteur, Antoniu Pop, Marc Pouzet, Annie Ressouche, Xavier Rival and Valérie Roy for their help, Laure Gonnord and Jean-Pierre Talpin for

This work was supported by the French National Research Agency, under grant ANR 2008 CORD 003 01. Authors' addresses: Karim Barkati, IRCAM, France; Pierre Jouvelot, CRI -MINES ParisTech, France.