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

playcap

v0.2.2

Published

Native access to speaker and microphone for Node.js

Downloads

22

Readme

PLAY🔊CAP🎙

Native access to speaker and microphone for Node.js.

Playcap is a module that provides native access to the microphone and speaker in a separate thread(s). Playcap is built on top of the miniaudio C library, so it supports a lot of platform-specific backends. Playcap working only with 32-bit floating-point format with [-1; 1] range.

Roadmap

  • [x] add the ability to select a backend
  • [ ] add the ability to stop (basically pause) device
  • [ ] add the ability to enable metadata for data callback(e.g. sampleRate, delta, currentTime)
  • [ ] add the ability to use fixed sample buffer size

Installation

Install playcap using npm:

npm install playcap

Introduction

First of all, if you are not familiar with the basics of DSP, (sample rate, bit depth, amplitude, frequency and so on) you can watch very good introduction videos in this youtube playlist. If you want go further I highly recommend the Hack Audio book.

Your first beep to start somewhere

Just a simple example that will beep for a second and then will be terminated.

const { Context, DeviceType } = require('playcap')

const SAMPLE_RATE = 44100;

const ctx = new Context()

const delta = 1.0 / SAMPLE_RATE
let currentTime = 0

const device = ctx.createDevice({
  sampleRate: SAMPLE_RATE,
  deviceType: DeviceType.Playback,
}, (input, output) => {
  for (let i = 0; i < output[0].length; i++) {
    const sample = Math.sin(Math.PI * 2 * 440 * currentTime)

    for (let channel = 0; channel < output.length; channel++) {
      output[channel][i] = sample
    }

    currentTime += delta
  }
})

device.start()

setTimeout(() => {
  device.destroy()
}, 1000)

You can notice several concepts in this code. First of all, it is Context. It represents an audio backend, for example, it can be CoreAudio for MacOs or ALSA for Linux. There is also another concept - Device. Device is an abstraction for a physical device that can capture or/and play audio. One Context can have multiple Devices, but only one Context for a particular Device. The last concept is DeviceType which determines how we will work with the device. In this case we use Playback type which tells us that we are only interested in the output.

The overall chain is quite simple. We create Context, then we create a Device based on Context and pass data callback (the function which will process audio) to the created device.

The data callback is a function that takes input in output. And the input and output are just arrays of Float32Array. Each Float32Array represents the audio channel, so the output array for 2 channels device will contain two Float32Array elements. You can notice that we don't have any information about the device in data callback (e.g. sample rate, delta, current time), so you can manage it manually (it will be probably added in future versions).

Dealing with device types

There are three device types:

  • Playback
  • Capture
  • Duplex

We have already met the first of them. The Playback device type means we are not interesting inputs, so it always will be zeros in the inputFloat32Array.

In contrast to the Playback type, the Capture type only provides us with input data. Writing to output elements will not affect anything. This will be useful, for example, if you want to record your banjo🪕 playing to an audio file.

The last one is quite interesting. Duplex device type provides access to both the input and output. So input elements will contain audio data from the microphone and output elements will provide writing access to the speaker. You can use this type if you want to hear how loud it is when your finger strikes the microphone membrane. One important note. You can have completely different physical devices, for example, external mic and speakers, but you can combine them into one virtual duplex device.

Even more easier example

const { Context, DeviceType } = require('playcap')

const ctx = new Context()

const device = ctx.createDevice({
  sampleRate: 44100,
  captureChannels: 1,
  deviceType: DeviceType.Duplex,
}, (input, output) => {
  for (let i = 0; i < input[0].length; i++) {
    for (let channel = 0; channel < output.length; channel++) {
      output[channel][i] = input[0][i]
    }
  }
})

device.start()

process.on('SIGINT', () => {
  device.destroy() // don't forget do that :)
})

We just copy numbers from one input channel to N output channels, that's it.

Api

Exports

  • Context
  • DeviceType
  • Backend

Context

new Context(backend: Backend): Context

Options:

  • backend: Backend - backend type

Methods:

  • getDevices(): DeviceInfo[] - returns list of devices
  • refreshDevices(): void - refresh list of devices
  • createDevice(options: DeviceOptions, dataCallback: DataCallback): Device - returns Device instance

Returns: Context instance


DeviceType

  • DeviceType.Playback
  • DeviceType.Capture
  • DeviceType.Duplex

Backend

  • Backend.Wasapi
  • Backend.Dsound
  • Backend.Winmm
  • Backend.Coreaudio
  • Backend.Sndio
  • Backend.Audio4
  • Backend.Oss
  • Backend.Pulseaudio
  • Backend.Alsa
  • Backend.Jack
  • Backend.Aaudio
  • Backend.Opensl
  • Backend.Webaudio
  • Backend.Custom
  • Backend.Null

DeviceOptions

  • playbackChannels: number - The number of output channels. Decided automatically if not specified
  • captureChannels: number - The number of input channels. Decided automatically if not specified
  • sampleRate: number - device sample rate
  • playbackDeviceIndex: number - index of playback device. The list of devices can be obtained by getDevices method. Decided automatically if not specified
  • captureDeviceIndex: number - index of capture device. The list of devices can be obtained by getDevices method. Decided automatically if not specified
  • deviceType: DeviceType - device type: Playback, Capture or Duplex

DeviceInfo

  • name: string - device name
  • isDefault: boolean - device is the default device

DataCallback

Data processing callback

(inputs: Float32Array[], outputs: Float32Array[]) => void;


Device

Methods

  • start(): void - run device
  • destroy(): void - destroy device. DO NOT use this method inside data callback, it will cause deadlock.