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

@musical-patterns/material

v1.0.143

Published

Takes whatever amazing craziness a given pattern calls for and materializes it.

Downloads

55

Readme

Musical Patterns - Material

Takes whatever amazing craziness a given pattern calls for and materializes it.

Consists of several components:

  • compiler
  • performer
  • snapshots
  • patterns utilities

Musical Patterns - Compiler

First it calls each of the "materialize" functions with the specs you've provided (or defaults to the pattern's initial specs). For example, you could materialize some Scales and Entities using specs provided through making selections in the UI of the @musical-patterns/playroom. The pattern's specs and materials are unique to each pattern, but their job is to together produce data the compiler can resolve. So, once thus materialized, the compiler reduces the large amount of data produced down to fundamental sound instructions for the performer.

usage

import { CompiledPattern, Material, setupPerformer, compilePattern } from '@musical-patterns/material'
import { StandardSpec } from '@musical-patterns/spec'

const material: Material = {
	materializeEntities,
}

const spec: MySpec extends StandardSpec = {
	// anything
}

const compiledPattern: CompiledPattern = await compilePattern({ material, spec })

setupPerformer({ compiledPattern })

terminology - high level

Scale

One of two things which are directly materialized, the other being Entities. Scales are the bedrock of your composition, in that they map values which are in virtual units such as Time and Frequency into physical units such as Ms and Hz. They also describe systems of numbers which are not experienced as music directly, but which are dereferenced by Entities as they make the music.

Entity

Entities are similar to tracks or performers. They are the more direct source of the resultant heard music. They are associated with a timbre. They also each have an array of Sections each of which has an array of Notes to play. Finally, they can have a delay (otherwise all Entities start getting busy on their Notes right away upon pressing play).

Voice

During compilation, Entities are compiled into Voices. Their Notes are compiled into Sounds. The idea is that Entities and Notes describe musical information in a way more readily understood by humans, while a Voice and its Sounds are the final, simplest form for the computer to play.

Section

Each Section has an array of Notes. It also has a property called repetitions, which is how many times it will play those notes before moving on to the next Section.

repetend

If a Section's repetitions property not specified, the assumption is that the Section should be repeated indefinitely (even if there are further Sections in the array). In this case, the Section is the Entity's "repetend".

segno

Italian for 'sign', this is the time position an Entity repeats from once it reaches its end. The segnoIndex is the index of a Sound in the Voice's array of Sounds. The segnoTime, on the other hand, is a time position in milliseconds.

This is a good example of the difference between human-styled Entities and computer-styled Voices: Entities still have their Notes organized into separate arrays, one per Section. A Voice, on the other hand, has collapsed all of its Sounds into a single array, having calculated and reduced down all the information from the Section organization into a single value, the segnoIndex. So it has lost some of the information about where humans might feel a section to be restarting, but if it doesn't matter for performance, it is not represented here.

terminology - low level

Block

Blocks are just arrays of numbers, a very abstract form of the pattern.

Rendering

A Rendering converts a Block to a ContourPiece. What Block and ContourPiece share in common is that each element will eventually become a Note. The key differences between a Block and a ContourPiece are:

  • A Block is an array of numbers, while a ContourPiece is an array of arrays of numbers.
  • Each element in a ContourPiece corresponds with a feature of a Note (such as duration, pitch, or gain).

ContourPiece

What you get after you map a Rendering onto a Block.

ContourPiece is the smallest compositional object of the pattern, too small to write the pattern in directly. Something like a bar in traditional Western music, I suppose. Really depends on the pattern though. You'll need to sequence several of them together into a ContourWhole to get something substantial next.

A ContourPiece type is parameterized with a type which describes which Feature each value describes. For instance, a PitchDurationGain parameter says that in a ContourElement (an element of a ContourPiece (or ContourWhole)), the first value is used for pitch, the second for duration, and the third for gain.

It does not specify how the value will be used be for that Feature, though. That is, the value in the slot for pitch may be used as a scalar directly, or it may be used as the index of a scalar in a Scale's array. See Feature below for more information on that.

If you find yourself writing a pattern for which more than one piece of information for a given feature needs to be described, you may need to get creative and design your own paramater for ContourElement. If you just need to provide both index and scaleIndex, you can solve your problem by using a parameter with "Scale" as one of the slots. That one is generic to Feature and is intended to be used for whatever Feature cares about scaleIndex. If you have more than one Feature which cares about scaleIndex, then yeah, get creative, good luck to you.

ContourWhole

A concatenation of several ContourPiece together; a large enough compositional object to write the pattern in directly; a ContourWhole is still intended to be compiled to something for just one Entity to play.

Segment

Take a set of ContourWhole, and each ContourWhole has all of its ContourElements mapped to a Note, and each ContourWhole's Note total the same duration, so they can be played simultaneously by different Entities, but still sequenced together with other Segments

Note

A Note is the final step in the materialization process - the final step before handing over to the compiler.

Feature

Each Feature of a Note is described using a subset of four properties:

  • scalar: This is the simplest method. The compiled value of this Feature will be the basis scaled by this amount. In this case, a Scale is not even used to determine the Feature.
  • index: Each Note is associated with a Scale, which has an array of Scalars. The compiler will pull the Scalar with this index from that array, and the compiled value of this Feature will be the basis scaled by that amount. If you use this property and scalar, then both Scalars will be applied.
  • scaleIndex: The compiler will override the default Scale for the Note. This property only matters if you are also using the index property.
  • translation: After any/all Scalars are applied, a Translation may be applied as well.

Performer

Given a compiled pattern, hooks it up to the Web Audio and WebXR APIs and gives you the power to play it (and pause it, etc.)

usage

setup

import { setupPerformer, OnUpdate } from '@musical-patterns/material'

const onUpdate: OnUpdate = time => {
	// do whatever you wanna do with the latest time here, such as update some display
	// note that the time this callback gets called with, if your pattern repeats from some point whenever it reaches the end, will restart to that time (it is not the raw time passed since starting the pattern in your reality; it is the time within the pattern)
}

await setupPerformer({ onUpdate })

This will ensure your browser is ready to start playing!

loading a pattern

import { setPattern, CompiledPattern } from '@musical-patterns/material'

const compiledPattern: CompiledPattern = {
	// your compiled pattern here
}

await setPattern(compiledPattern)

setPattern only sets what is to be performed. It does not start playing it yet.

starting and stopping

import { play, pause, stop } from '@musical-patterns/material'

# set paused to true
pause()
# set paused to false
play()
# or set paused to false plus reset the time to 0
await stop()

enabling immersive audio

import { enableImmersiveAudio } from '@musical-patterns/material'
import { buildVrb } from 'vrb'

const homePosition: Coordinate = [ 5, 4, 3 ]
const onReady: VoidFunction = () => {
	// do whatever you want once the VR device is ready
}
const onNoVr: VoidFunction = () => {
	// do whatever you want once it is determined that your system does not support VR
}

const toggleImmersiveAudioHandler: VoidFunction = enableImmersiveAudio({ vrb, homePosition, onReady, onNoVr })

const toggleImmersiveAudioButton = document.createElement('div')
toggleImmersiveAudioButton.innerText = 'Toggle Immersive Audio'
toggleImmersiveAudioButton.addEventListener('click', toggleImmersiveAudioHandler)
document.body.appendChild(toggleImmersiveAudioButton)

If you have your own instance of Vrb (https://www.npmjs.com/package/vrb) you may inject it here. If you do not, Vrb is what will be used under the hood for WebVR and it will be automatically configured to reasonable defaults for you.

or if you're an eager beaver

If you pass voices to the setup, it will automatically start playing them.

import { compilePattern, setupPerformer, CompiledPattern } from '@musical-patterns/material'
import { pattern } from '@musical-patterns/pattern-houndstoothtopia-theme'

const compiledPattern: CompiledPattern = await compilePattern(pattern)
await setupPerformer({
	compiledPattern,
})

jumping around in time

import { setTime } from '@musical-patterns/material'

await setTime(14000)

It will keep playing if it was playing already.

Snapshot

Similar to the @musical-patterns/cli repo, upon installation, copies snapshot files into the pattern repo.

These files are:

  • Makefile.snapshots
  • test/snapshots.test.ts

When inside the directory of a pattern for which you want to update the snapshot, run:

musical-patterns-snapshots

Or make snapshots since the Makefile.snapshots aliases it like that.

Uses the compiler to maintain an up-to-date copy of compiled pattern data in the repo. This snapshots.json file is tested against before each shipment, ensuring your pattern doesn't change if you don't mean it to. It tests your initial specs as well as the specs for each preset.