npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

melo

v0.0.0

Published

Low-level language for audio/signal purposes

Downloads

28

Readme

melo stability test

Micro language for floatbeats and audio with smooth operator and organic sugar. Compiles to compact 0-runtime WASM with linear memory.

Reference

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ numbers
16, 0x10, 0b0;               \\ int, hex or binary
16.0, .1, 1e3, 2e-3;         \\ float

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ operators
+ - * / % -- ++              \\ arithmetical (float)
** %% //                     \\ power, unsigned mod, floor div
& | ^ ~ >> <<                \\ binary (integer)
<<< >>>                      \\ rotate left, right
&& || !                      \\ logical
> >= < <= == !=              \\ comparisons (boolean)
?: ?                         \\ conditions
a..b                         \\ ranges
~ ~= ~/ ~* ~// ~**           \\ clamp, normalize, lerp
^ ^^ ^^^                     \\ continue, break, return
x[i] x[]                     \\ member access, length
|> %                         \\ pipe, loop

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ variables
foo=1, bar=2.0;              \\ declare vars
AbCF, $0, Δx, _;             \\ names permit alnum, unicodes, _$
fooBar123 != FooBar123;      \\ case-sensitive
default=1, eval=fn, else=0;  \\ freedom of speech
true = 0b1, false = 0b0;     \\ alias bools
inf = 1/0, nan = 0/0;        \\ alias infinity, NaN

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ units
1k = 1000; 1pi = 3.1415926;  \\ define units
1s = 44100; 1m = 60s;        \\ useful for sample indexes
10.1k, 2pi;                  \\ 10100, 6.283...
2m35s;                       \\ combinations

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ statements
a, b=1, c=2;                 \\ declare vars in C style
foo();                       \\ semi-colons are mandatory
(c = a + b; c);              \\ group returns last statement
(a = b+1; a,b,c);            \\ return multiple values
(a ? ^b; c);                 \\ break current scope, return b
((a ? ^^; c); d);            \\ break 2 scopes
(((a ? ^^^; c); d); e);      \\ break to the root scope

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ conditions
a ? b;                       \\ if a then b (question operator)
a ?: b;                      \\ if not a then b (elvis operator)
sign = a < 0 ? -1 : +1;      \\ ternary conditional
(2+2 >= 4) ? log(1) :        \\ multiline/switch
  3 <= 1..2 ? log(2) :       \\ else if
  log(3);                    \\ else
a && b || c;                 \\ (a and b) or c

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ groups
(a,b,c) = (d,e,f);           \\ assign (a=d, b=e, c=f)
(a,b) = (b,a);               \\ swap
(a,b,c) = d;                 \\ duplicate: (a, b, c) = (d, d, d);
(a,,b) = (c,d,e);            \\ skip: (a=c, d, b=e);
(a,b) + (c,d);               \\ any operator: (a+c, b+d)
(a, b, c)++;                 \\ (a++, b++, c++)
(a,b)[1] = c[2,3];           \\ props: (a[1]=c[2], b[1]=c[3])
a = (b,c,d);                 \\ a=b; a=c; a=d; (see loops)

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ranges
0..10;                       \\ from 1 to 9 (10 exclusive)
0.., ..10, ..;               \\ open ranges
10..1;                       \\ reverse range
1.08..108.0;                 \\ float range
(a-1)..(a+1);                \\ computed range
(a,b,c) = 0..3 * 2;          \\ a=0, b=2, c=4
a ~ 0..10; a ~= 0..10;       \\ clamp(a, 0, 10); a = clamp(a, 0, 10);
a ~/ 0..10; a ~* 0..10;      \\ normalize(a, 0, 10); lerp(a, 0, 10);
a ~// 0..10; a ~** 0..10;    \\ smoothstep(a, 0, 10); ismoothstep(a, 0, 10);

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ arrays
m = [..10];                  \\ array of 10 elements
m = [..10 |> 2];             \\ filled with 2
m = [1,2,3,4];               \\ array of 4 elements
m = [n[..]];                 \\ copy n
m = [1, 2..4, 5];            \\ mixed definition
m = [1, [2, 3, [4]]];        \\ nested arrays (tree)
m = [i = 0..4 |> i ** 2];    \\ list comprehension
(first,last) = (m[0], m[-1]);\\ get by index
(second, ..last) = m[1, 2..];\\ get multiple values
length = m[];                \\ get length
m[0] = 1;                    \\ set value
m[2..] = (1, 2..4, n[1..3]); \\ set multiple values from offset 2
m[0..] = 0..4 * 2;           \\ set from range
m[1,2] = m[2,1];             \\ swap
m[0..] = m[-1..0];           \\ reverse order
m[0..] = m[1..,0];           \\ rotate
min ~=..m[..], max ~=m[..]..;\\ find min/max in array

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ loops
i = a, b, c |> f(i);         \\ for each item in a, b, c do f(item)
i = 10.. |> (                \\ descend over range
  i < 5 ? ^;                 \\ if item < 5 continue
  i < 0 ? ^^;                \\ if item < 0 break
);                           \\
x[..] |> f(%) |> g(%);       \\ sequence of ops
x[..] |> % * 2 |> y[..];     \\ write to destination
i = 0..w |> (                \\ nest iterations
  j = 0..h |> f(i, j);       \\ f(x,y)
);                           \\
(x,,y) = (a,b,c |> % * 2);   \\ x = a * 2, y = c * 2;
.. |> i < 10 ? i++ : ^;      \\ while i < 10 i++
..(i < 10) / 0 |> i++;       \\ alternative while

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ functions
double(n) = n*2;             \\ define a function
times(m = 1, n ~ 1..) = (    \\ optional, clamped arg
  n == 0 ? ^n;               \\ early return
  m * n                      \\ default return
);                           \\
times(3,2);                  \\ 6
times(5);                    \\ 5 - optional argument
times(,10);                  \\ 10 - skipped argument
copy = triple;               \\ capture function
copy(10);                    \\ also 30
dup(x) = (x,x);              \\ return multiple values
(a,b) = dup(b);              \\ multiple returns

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ state vars
a() = ( *i=0; ++i );         \\ i persists value between calls
a(), a();                    \\ 1, 2
fib() = (                    \\
  *i=[1,0,0];                \\ local memory of 3 items
  i[1..] = i[0..];           \\ shift memory
  i[0] = i[1] + i[2];        \\ sum prev 2 items
);                           \\
fib(), fib(), fib();         \\ 1, 2, 3
c() = (fib(), fib(), fib()); \\ state is defined by fn scope
fib(); c();                  \\ 5; 1, 2, 3;
d(fn) = (fib(), fn());       \\ to get external state, pass fn as argument
d(c);                        \\ 1, 8;

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ export
x, y, z                      \\ exports last statement

Examples

Provides k-rate amplification for block of samples.

gain(                             \\ define a function with block, volume arguments.
  block,                          \\ block is a array argument
  volume ~ 0..100                 \\ volume is limited to 0..100 range
) = (
  block[..]
    |> % * volume                 \\ multiply each sample by volume value
    |> block[..]
);

gain([0..5 * 0.1], 2);            \\ 0, .2, .4, .6, .8, 1

gain                              \\ export gain function

Minifies as gain(b,v)=b[..]|>%*v|>b[..]

A-rate (per-sample) biquad filter processor.

1pi = pi;                         \\ define pi units
1s = 44100;                       \\ define time units in samples
1k = 10000;                       \\ basic si units

lpf(                              \\ per-sample processing function
  x0,                             \\ input sample value
  freq = 100 ~ 1..10k,            \\ filter frequency, float
  Q = 1.0 ~ 0.001..3.0            \\ quality factor, float
) = (
  *(x1, y1, x2, y2) = 0;          \\ define filter state

  \\ lpf formula
  w = 2pi * freq / 1s;
  sin_w, cos_w = sin(w), cos(w);
  a = sin_w / (2.0 * Q);

  b0, b1, b2 = (1.0 - cos_w) / 2.0, 1.0 - cos_w, b0;
  a0, a1, a2 = 1.0 + a, -2.0 * cos_w, 1.0 - a;

  b0, b1, b2, a1, a2 *= 1.0 / a0;

  y0 = b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2;

  x1, x2 = x0, x1;            \\ shift state
  y1, y2 = y0, y1;

  y0                              \\ return y0
);

\\ i = [0, .1, .3] |> lpf(i, 108, 5);

lpf                               \\ export lpf function, end program

Generates ZZFX's coin sound zzfx(...[,,1675,,.06,.24,1,1.82,,,837,.06]).

1pi = pi;
1s = 44100;
1ms = 1s / 1000;

\\ define waveform generators
oscillator = [
  saw(phase) = (1 - 4 * abs( round(phase/2pi) - phase/2pi )),
  sine(phase) = sin(phase)
];

\\ applies adsr curve to sequence of samples
adsr(
  x,
  a ~ 1ms..,                    \\ prevent click
  d,
  (s, sv=1),                    \\ optional group-argument
  r
) = (
  *i = 0;                       \\ internal counter, increments after fn body
  t = i / 1s;

  total = a + d + s + r;

  y = t >= total ? 0 : (
    t < a ? t/a :               \\ attack
    t < a + d ?                 \\ decay
    1-((t-a)/d)*(1-sv) :        \\ decay falloff
    t < a  + d + s ?            \\ sustain
    sv :                        \\ sustain volume
    (total - t)/r * sv
  ) * x;
  i++;
  y
);

\\ curve effect
curve(x, amt~0..10=1.82) = (sign(x) * abs(x)) ** amt;

\\ coin = triangle with pitch jump, produces block
coin(freq=1675, jump=freq/2, delay=0.06, shape=0) = (
  *out=[..1024];
  *i=0;
  *phase = 0;                   \\ current phase
  t = i / 1s;

  \\ generate samples block, apply adsr/curve, write result to out
  out[..] = (
    i = out[..]
      |> oscillator[shape](phase)
      |> adsr(i, 0, 0, .06, .24)
      |> curve(i, 1.82)
  );

  i++;
  phase += (freq + (t > delay && jump)) * 2pi / 1s;
).

See all examples

Usage

melo is available as CLI or JS package.

npm i melo

CLI

melo source.melo -o dest.melo

This produces compiled WASM binary.

JS

import melo from 'melo'

// create memory buffer (optional)
const memory = new WebAssembly.Memory({
  initial: 10,
  maximum: 100,
});

// create wasm arrayBuffer
const buffer = melo.compile(`
  n=1;
  mult(x) = x*PI;
  arr=[1, 2, sin(1.08)];
  mult, n, arr;
`, {
  // js objects or paths to files
  imports: {
    math: Math,
    mylib: './path/to/my/lib.melo'
  },

  memory,

  // target: `wat` for text or `wasm`
  target: 'wasm'
})

// create wasm instance
const module = new WebAssembly.Module(buffer)
const instance = new WebAssembly.Instance(module, {
  imports: {math: Math}
})

// use API
const { mult, n, arr } = instance.exports

// number exported as global
n.value = 2;

// function exported directly
mult(108) // 216

// array is a number pointer to memory
const arrValues = new Float64Array(memory, arr.value, 3)

Motivation

Melo is personal take on what would well designed language look like. It has narrow focus - audio processing & DSP, mainly to give advantage over JS / Web Audio in terms of performance & memory.

Web Audio is unreliable - it has unpredictable pauses, glitches and so on, so audio is better handled in WASM worklet (@stagas). Besides, audio processing in general has no cross-platform solution, various environments deal with audio differently, some don't have audio processing at all. Good old audio code gets dated, in 20 years most of the soft is unable to run.

So melo attempts to fill that gap, trying to provide a standard layer. WASM enables it for browsers, audio/worklets, web-workers, nodejs, embedded systems and any other envs. In the future it aims at GL and JS as compile targets.

Inspiration

mono, zzfx, bytebeat, glitch, hxos, min, roland, porffor

Acknowledgement

  • @stagas for initial drive & ideas
  • for package name