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

phet-osc-bridge

v1.0.3

Published

A bridge between PhET and sound synthesis applications using Open Sound Control

Downloads

10

Readme

PhET to Open Sound Control Bridge

The PhET OSC Bridge provides a means for sending events fired by a PhET physics simulation, wrapped with PhET-iO, to remote processes using the Open Sound Control protocol. The purpose of this bridge is to make it easier for sound designers to use familiar audio synthesis tools such as Max and SuperCollider, to quickly prototype sonifications for PhET.

Useful Links

Architecture

The PhET OSC Bridge includes several components:

  1. A client-side JavaScript component, the phetosc.bridge that can be added to any PhET-iO wrapper HTML page to listen for sim events.
  2. A web server that serves up PhET-iO wrapper HTML pages, and responds to incoming Web Socket requests from the client-side bridge component.
  3. An OSC output port (configured to use UDP by default) that relays OSC messages to the the remote server (e.g. SuperCollider or Max).

Using the PhET OSC Bridge

Getting Set Up

First, follow the instructions provided with your PhET-iO license to generate an appropriate wrapper HTML page. More information is available in the PhET-iO Developer's Guide.

Secondly, install the phet-osc-bridge npm module:

npm install -g phet-osc-bridge

Adding the Bridge Component to your PhET-iO Wrapper

The PhET OSC Bridge web server will serve up the required client JavaScript file. You just need to add it to your PhET-iO wrapper's head using a script tag:

<script type="text/javascript" src="/phet-osc-bridge/phet-osc-bridge.js"></script>

Next, you'll need to instantiate the bridge component and bind it to the PhET sim's simIFrameClient object. This will cause all events emitted from the sim to be available across the bridge. Paste this code into the onSimInitialized event handler function that is included in your wrapper's call to simIFrameClient.launchSim():

var simIFrameClient = new SimIFrameClient(document.getElementById("sim"));

simIFrameClient.launchSim(sim.URL, {
    onSimInitialized: function () {
        var oscBridge = phetosc.bridge();
        oscBridge.bind(simIFrameClient);
    }
});

Starting the Bridge's Server

Lastly, you'll need to start the PhET OSC Bridge server. In your terminal, navigate to the directory in which your PhET-iO wrapper files are located, and run:

phet-osc-bridge --phetPath .

By default, your wrapper file will be available in your web browser at http://localhost:8081/<wrapper-file-name>.

Server Configuration Options

Other configuration options can be specified on the command line. More information can be found by running the phet-osc-bridge command with the --help flag.

Bridge Options

The phetosc.bridge component provides a variety of configuration options, which are described in the sections below.

Filtering Events

In many cases, only a subset of events are relevant for a sonification. The phetioIDPatterns option allows you to specify an array of regular expression patterns that will be matched against the phetioID of events. Only those events with a phetioID matching one of the regular expressions specified in phetioIDPatterns will be converted and sent via OSC (i.e. the patterns are ORed together).

Example: Listening Only for Particle Count Change Events

var oscBridge = phetosc.bridge({
    phetioIDPatterns: [
        "buildAnAtom.atomScreen.model.particleAtom.particleCountProperty"
    ]
});

Excluding Parameters

Some parameters may not be relevant for sonification, such as the oldValue parameter that is specified whenever a property changes. The excludeParameters option can be specified to filter out parameters by name.

Example: Filtering out oldValue Parameters

var oscBridge = phetosc.bridge({
    excludeParameters: [
        "oldValue"
    ]
});

Mapping OSC Addresses

By default, PhET OSC Bridge will use a long-form address space like this:

/<phetioID>/<event>/<name>/<parameter>/<parameter value key>

In some cases, however, you may want to map the outgoing OSC messages to a simpler address space. The addressMap option allows you to provide alternative addresses for specified events. This option should provide, as key, the long-form OSC address you'd like to map; the value is the new address.

<long form event address>: <mapped address>

Example: Mapping the OSC Address for Particle Count Changes

var oscBridge = phetosc.bridge({
    addressMap: {
        "/buildAnAtom.atomScreen.model.particleAtom.particleCountProperty/model/changed/newValue": "/particleCount"
    }
});

PhET -> OSC Implementation Details

Open Sound Control message payloads are flat; there is no way to send named parameters, dictionaries, or objects within an OSC message. PhET events, however, represent changes within a hierarchical value space consisting both of user interface components and model properties. When binding PhET events to OSC, a message denotes a change to a single value within an object that is uniquely identified by the structure of the OSC message's address.

Types of PhET Events

  • User: triggered by a user action
  • Model: a change in the simulation's state

Structure of a PhET Event

  • Events are hierarchical; they can contain children events that "were triggered while this event was being processed." In this OSC binding, we have flattened the parent/child event structure, treating them as a flat sequence of events.
  • Events are fired by objects, which are uniquely identified by keypath-style structures ("foo.bar.baz").

Binding PhET Events to OSC Addresses

In order to accurately map JSON objects to OSC messages, each event can be represented as an OSC bundle. Each property of each event parameter is a separate message within the bundle.

/<phetioID>/<event>/<name>/<parameter>/<parameter value key>

Since bundles can sometimes be inconvenient to work with in environments like SuperCollider or Max, the bundleParameters option can be set to false to send unbundled messages. This is the default.

Example PhET to OSC Transformations

Example 1: User Dragged a Proton Event

{
  packets: [
    {
      address: "/buildAnAtom.atomScreen.view.nucleons_9.inputListener/user/dragged/x",
      args: [
        type: "d",
        value: "473"
      ]
    },
    {
      address: "/buildAnAtom.atomScreen.view.nucleons_9.inputListener/user/dragged/y",
      args: [
        type: "d",
        value: "148"
      ]
    }
  ]
}

Example 2: Model "Proton No Longer Under User Control" Event

{
  packets: [
    {
      address: "/buildAnAtom.atomScreen.model.protons_9.userControlledProperty/model/changed/oldValue",
      args: [
        type: "b",
        value: true
      ]
    },
    {
      address: "/buildAnAtom.atomScreen.model.protons_9.userControlledProperty/model/changed/newValue",
      args: [
        type: "b",
        value: false
      ]
    }
  ]
}

Example 3: A Primitive Property Value

PhET Event JSON Structure

{
  "messageIndex": 179,
  "eventType": "model",
  "phetioID": "buildAnAtom.atomScreen.model.particleAtom.particleCountProperty",
  "componentType": "TDerivedProperty",
  "event": "changed",
  "time": 1490762584752,
  "parameters": {
    "oldValue": 0,
    "newValue": 1
  }
}

OSC Bundle JSON Structure

{
  packets: [
    {
      address: "/buildAnAtom.atomScreen.model.particleAtom.particleCountProperty/model/changed/newValue",
      args: [
        {
          type: "d",
          value: 1
        }
      ]
    }
}

Example 4: An Object Value

PhET Event JSON Structure

{
  "messageIndex": 185,
  "eventType": "model",
  "phetioID": "buildAnAtom.atomScreen.model.protons_9.positionProperty",
  "componentType": "TProperty",
  "event": "changed",
  "time": 1490762584782,
  "parameters": {
    "oldValue": {
      "x": -26.402555910543136,
      "y": -26.2194249201278
    },
    "newValue": {
      "x": -20.016486181288922,
      "y": -19.8776496629066
    }
  }
}

OSC Bundle: Object Value

{
  packets: [
    {
      address: "/buildAnAtom.atomScreen.model.protons_9.positionProperty/model/changed/newValue/x",
      args: [
        {
          type: "d",
          value: -20.016486181288922
        }
      ]
    },
    {
      address: "/buildAnAtom.atomScreen.model.protons_9.positionProperty/model/changed/newValue/y",
      args: [
        {
          type: "d",
          value: -19.8776496629066
        }
      ]
    }
  ]
}