Learn how we set out to build a plugin for musicians and ended up creating a progressive file system that grows with the user's needs.

Ditto

Our Fissioneers love pushing the boundaries of the ODD SDK to unlock new features and use cases. Recently, engineers Brian and Andy did just that with Ditto.

Ditto is a VST delay plugin. Users can create their own delay presets in the app and use the Ditto Companion web app to share and collect Ditto presets.

Elementary

Ditto uses Elementary, a JavaScript framework and high-performance audio engine that makes developing audio plugins using web technologies easier.

Ditto uses the @elemaudio/plugin-renderer, which runs a web app in WebView inside of a VST binary. The WebView gives us a browser environment where we can run Webnative. This makes development much more accessible because you don't need to know C++ - only JavaScript.

Here is the Ditto plugin loaded into Bitwig Studio:

ditto-in-bitwig

Preset Manager

Audio plugins typically have a system for saving presets, which captures plugin state and metadata about the preset. We implemented presets in Ditto that store plugin state, notes, tags, and favorite status:

ditto1

The presets interface is organized by categories, including All, Favorites, and categories automatically generated from preset tags.

Progressive File System Enhancement

Plugin users expect plugins to store presets without signing into an account. To match those expectations, our first experiment with Ditto was to implement a local-only file system that does not require sign-in and an optional synced file system that requires an account. When a user decides to create an account, their presets are copied from the local-only file system to a file system associated with a username and persisted to Fission IPFS nodes.

Each file system is associated with an app namespace to keep them separate in browser storage. We determine which file system to use by checking whether the user has created an account.

In application programming, we're often trained to think about how we will serve users now and how we want to serve them down the line. We build the infrastructure to allow us to introduce new planned features without creating more work for us later on.

This is sensible, but what if, as a developer, you want to ship your minimum viable product now, gather feedback, and then add syncing and sharing later?  

Users are also tired of signing up for endless platforms, not knowing if it will be the right tool for them. Why not give them the option to get hands-on with the tool first, and if/when they decide to access more features, you ask them to make an account (a password-less one, of course!)?

Building using a progressive file system not only reduces the scope of an MVP, it also removes a common barrier to adoption!

Connecting to Ditto Companion

When the user is ready to go beyond the local-only file system, they can create an account and connect to the Ditto Companion app.

pick-username

First, they create a username and select "connect." Then they are given a QR code and a connection link.

connection-link

The QR Code and connection link open Ditto Companion and use the AWAKE protocol to begin device-linking.

companion-app

The user enters the code shown in Ditto Companion into Ditto:

enter-code

After entering the code, Ditto shows the user a message confirming they have connected with Ditto Companion:

connected

The user can connect again later if they would like to connect to another browser or device.

Namespaces

The Ditto plugin and Ditto Companion use distinct app namespaces. However, by using UCAN authorization and transmitting the user's WNFS encryption key, the Ditto Companion app shares the synced file system with the Ditto plugin.

Having multiple namespaces also makes it possible for users to work on several apps locally. It used to be that you could only work on one app at a time on localhost:8080 for example, but namespacing puts them each in their own box, so to speak, and you can switch from one app to another without thinking about it.

Sharing and Collecting Presets

As mentioned earlier, Ditto Companion is a web app for sharing and collecting presets.

We started Ditto Companion from the ODD App Template. Our connect flow is simplified compared to the complete feature set provided in the template - we only link from the plugin to the companion app. This simple model meant we could remove quite a bit from the template for our use case.

Our second experiment was to implement a lightweight share and collect system in the companion app. Shared presets are stored in the public WNFS tree. Presets that are not shared are in the private tree. Users share presets in the companion app:

share

They can also collect shared presets from other users. After selecting the plus button, they enter the username they want to collect from:

find-presets

Ditto Companion then checks whether a file system exists for the user. If a file system exists, we get a link for the public tree and check for a presets directory.

searching

If presets are found, we add them to the Collect tab:

found-presets

Users collect presets by checking the Collect checkbox for the preset. Collected presets are copied into the user’s file system, and the user can load them in the plugin after a refresh.

This sharing mechanism is very exciting because it searches for and scans public IPFS data and saves it to the user's file system, adding a level of interactivity to non-blockchain-based decentralized web apps. And because users can move their data to any Webnative-enabled app, there are many opportunities for collaboration and remixing of data.


Here is a full walkthrough of Ditto and Ditto Companion:

What do you think of Ditto? Are you building an app that would benefit from a progressive file system? Join our Discord community and share your feedback and thoughts!