Giter VIP home page Giter VIP logo

mimium-rs's Introduction

mimium (v2)

Test(main) Test(dev)

a programming language as an infrastructure for sound and music


mimium(MInimal-Musical-medIUM) is a programming language for sound and music.

mimium is made to be an infrastructure for distributing music in a form of a source code, not only a tool for musicians and programmers.

Its semantics are technically inspired from several modern programming languages for sound such as Faust and Extempore..

A minimal example below generates a sinewave of 440Hz.

// minimal.mmm
let twopi = 3.141595*2
let sr = 48000
fn dsp(){
  sin(now * 440 * twopi / sr)
}

This repository is a mimium Version 2, all the code base is rewritten in Rust while the original was in C++, and Semantics of the language was re-designed. The code is still very under development.

Overview of the new compiler-pipeline

  • Source code -> tokenizer -> parser -> AST โ†“
  • Removing "self" -> Type Inference & SSA Conversion -> MIR(Imperative)
  • VM ByteCode Generation

Roadmap tp version 2

  • Basic Data Types
    • AST
    • MIR
    • VM Instructions
  • Aggregate Types
    • Tuple (Vector) types
  • Compilers
    • Stateful Functions
      • Feedback with self
      • Delay and mem
    • Parser
    • MIR Generation
      • Type Inference
      • Code Generation
    • VM Code Generation
  • Runtime
    • Audio Driver Backend
      • CPAL implmentation
    • Logical Scheduler
      • auto de-allocation of unused closure
      • destructive assignment of closure upvalues
      • schedule (@) operator
    • Runtime value
      • now
      • samplerate
    • VM
      • Closure upvalue implementation
      • StateStorage implementation
    • simple file include
    • simple audio file reader function
      • array(slice) type & automatic interporation

Further Plans

  • Multi-stage computation (Hygienic Macro)
  • Generics
  • Native & WASM backend with Cranelift
  • Module System, Package Manager
  • effect system for managing statefull function and IO

other todos: Migrating examples

The source code is lisenced under Mozilla Puclic License 2.0.

Acknowledgements

This project is supported by all the contributers, Sponsors, grants and scholarships as follows.

  • 2019 Exploratory IT Human Resources Project (The MITOU Program) by IPA: INFORMATION-TECHNOLOGY PROMOTION AGENCY, Japan.
  • Kakehashi Foundation

mimium-rs's People

Contributors

tomoyanonymous avatar yutannihilation avatar

Stargazers

 avatar kenmatsu4 avatar Yusuke Saito avatar A1219 avatar Kentaro "zigen" Teramoto avatar  avatar Shinichi Tanaka avatar

Watchers

James Cloos avatar  avatar Shinichi Tanaka avatar  avatar  avatar

Forkers

yutannihilation

mimium-rs's Issues

Proposal: Plugin System

Currently, the scheduler is coupled with audio driver.

However, it can be decoupled as a separated module by defining a trait that has multiple callback such as a system wakeup, processing a buffer and processing sample.

This will be also useful for defining modules as a separated crate which depends on external crate, such as Symphonia for audio file reader and RtMidi for midi driver.

pub trait Plugin{
 fn get_extern_fns(&mut self)-> &[ExtFunType];
 fn get_extern_cls(&mut self)-> &[ExtClsType];
 fn on_system_launch(&mut self);
 fn on_process_block(&mut self,buf: &SampleBuffer);
 fn on_process_sample(&mut self, samples : &[Sample]);
 fn on_system_end(&mut self);
}

`LazyCell` should not be `const`

While this isn't a problem at the moment, I see this clippy warning (if you are using VS Code, you can set rust-analyzer.check.command option to clippy to always see such warnings, but it might be a bit annoying):

warning: a `const` item should not be interior mutable
   --> mimium-lang\src\runtime\builtin_fn.rs:231:1
    |
231 | / pub const BUILTIN_FNS: LazyCell<[BuiltinFn; 49]> = LazyCell::new(|| {
232 | |     [
233 | |         i_i!(neg),
234 | |         i_i!(not),
...   |
306 | |     ]
307 | | });
    | |___^
    |
    = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
    = note: `#[warn(clippy::declare_interior_mutable_const)]` on by default

The explanation of declare_interior_mutable_const says:

Consts are copied everywhere they are referenced, i.e., every time you refer to the const a fresh instance of the Cell or Mutex or AtomicXxxx will be created, which defeats the whole purpose of using these types in the first place.

I think I've heard about this problem, but forgot how to deal with this (static LazyLock?). Let me file this here for now.

Implement Scheduler

Because the closure and higher-order function can be realized in this implementation, Temporal recursion can be extended to more functional style, not just updating variable over time with destructive assignment by wrapping value like this.

fn generator(init:float, interval:float){
  let v = init // this v is captured and closed with recursive "updater" function
 let updater = | |{
     v = v+1
     updater()@(now+interval)
 }
 updater()@0;
 v
}

Refactor comment parser

Currently, inline comment //comment inside function definition fails to parse.
The parser should be changed so that it can ignore comment token at anywhere in the process.
We can remove all the comment tokens before parsing but it maybe better to keep it as a metadata for the following expression id because it can be extended as an attribute or documentation comment system.

Pipe operator

I experimentally implemented a pipe operator, and got to know there are two types of pipes.

cf. https://github.com/tc39/proposal-pipeline-operator?tab=readme-ov-file#why-the-hack-pipe-operator

  • explicit function call (Hack pipe): value |> foo(%)
  • implicit function call (F# pipe): value |> foo

It seems my implementation is a simpler version of "Hack pipe," which is without the placeholder % by assuming the value is inserted into the first argument. Since my main language is R, I naturally assumed this is the pipe operator. On the other hand, Mimium's pipe is "F# pipe". I think this needs some discussion because both pipe have their pros and cons.

Is it common to use the F# style in this area? If I understand correctly, F#'s pipe is designed for combination with partial application. I'm wondering if there's any plan.

(I'm asking this simply because it looks easy to implement. Not sure about the importance of the feature itself)

Remove unstable feature to switch from a nightly channel to the stable

  • #![feature(box_patterns)] if we use arena for recursive types, no longer needed(maybe match_deref crate macro can be used for simple matching)
  • #![feature(iterator_try_collect)] itertools can be used
  • #![feature(iter_collect_into)] used only one location in typing.rs, no need to persist with this feature
  • #![feature(if_let_guard)] no longer used in current code, can just remove
  • #![feature(lazy_cell)] stabilized in v1.8.0, just remove it and set the minimum compiler version

Use `id_arena` and `InternedString` in the compiler

In the current implementation, compiler clones many String value and comparing them.
Use StringInterner crate will improve the performance.

https://docs.rs/string-interner/latest/string_interner/

Also, recursive type definitions in the Expr and Type are realized simply with Box<Self>, however, this this will make a implementation
of interactive inspection of values difficult, for example, for the language server. Using id_arena simplifies this situation, along with performance improvements.

They are tested on my another project otopoiesis (an experimental branch)

https://github.com/tomoyanonymous/otopoiesis/blob/372bfb7b5c760744f69532c63e8804878a84397d/otopoiesis_lang/src/expr.rs#L31-L32

https://github.com/tomoyanonymous/otopoiesis/blob/372bfb7b5c760744f69532c63e8804878a84397d/otopoiesis_lang/src/lib.rs#L25-L28

Builtin function is overwritten by user-defined function

This code returns 0.0. It seems this user-defined function div is used for / operation because / simply calls a function with the name of Op::get_associated_fn_name(). Is this for allowing users to override the operators? If not, probably add _mimium_ prefix to the builtin functions and prohibit the use of the prefix (until namespace is implemented?).

fn div(x, y) {
    0.0
}
fn dsp(){
    1.0 / 1.0
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.