Skip to main content

Serial client for Plus Deck 2C PC Cassette Drive

Project description

Plus Deck 2C PC Cassette Deck

The Plus Deck 2C is a cassette deck that mounts in a 5.25" PC drive bay and is controlled over RS-232 serial. It was intended for archiving cassette tapes to mp3 - note that it can not write to cassettes. Here's the Amazon page for it:

https://www.amazon.com/Plusdeck-2c-PC-Cassette-Deck/dp/B000CSGIJW

It was initally released in the 2000s, and they are currently difficult to find. However, I always wanted one as a teenager and, as an adult, bought one for Too Much Money, and am currently writing modern tools for using it in a modern PC.

This project contains a Python library for interacting with the Plus Deck 2C over serial, using asyncio.

Install

plusdeck is a Python package, and therefore can be installed from PyPi, for instance with pip:

pip install plusdeck

In addition, I have a Fedora package on COPR, which can be installed like so:

sudo dnf copr enable jfhbrook/joshiverse
sudo dnf install plusdeck

Usage

Here's a basic example:

import asyncio

from plusdeck import connection


async def main():
    # Will close the client on exit
    async with connection("/dev/ttyS0") as client:
        # Play the tape
        client.play_a()

asyncio.run(main())

This will play the tape on side A, assuming it has been inserted into the Plus Deck.

The client has methods for every other command supported by the Plus Deck 2C as well:

method behavior
play_a Play side A
play_b Play side B
fast_forward_a Fast-forward side A (equivalent to rewinding side B)
fast_forward_b Fast-forward side B (equivalent to rewinding side A)
rewind_a Rewind side A (equivalent to fast-forwarding side B)
rewind_b Rewind side B (equivalent to fast-forwarding side A)
pause Pause or unpause playback
stop Stop the tape
eject Eject the tape

Subscribing to Events

The Plus Deck 2C will, if commanded to do so, emit its state on an interval. The client will deduplicate these states and emit changes as events. The most idiomatic way to interact with these events is to use the session method to access a Receiver, which allows for both "expecting" a state change and iterating over changes in state. The "expect" API looks like this:

import asyncio

from plusdeck import connection, State


async def main():
    async with connection("/dev/ttyS0") as client:
        # Access a receiver - will unsubscribe when the context manager exits
        async with client.session() as rcv:
            # Wait for the tape to eject
            await rcv.expect(State.EJECTED)

asyncio.run(main())

Iterating over state changes looks like this:

import asyncio

from plusdeck import connection


async def main():
    async with connection("/dev/ttyS0") as client:
        async with client.session() as rcv:
            # Print out every state change
            async for state in rcv:
                print(state)

asyncio.run(main())

CLI

This library has a CLI, which you can run like so:

$ plusdeck --help
Usage: plusdeck [OPTIONS] COMMAND [ARGS]...

  Control your Plus Deck 2C tape deck.

Options:
  --global / --no-global          Load the global config file at
                                  /etc/plusdeck.yaml (default true when called
                                  with sudo)
  -C, --config-file PATH          A path to a config file
  --log-level [DEBUG|INFO|WARNING|ERROR|CRITICAL]
                                  Set the log level
  --port TEXT                     The serial port the device is connected to
  --output [text|json]            Output either human-friendly text or JSON
  --timeout FLOAT                 How long to wait for a response from the
                                  device before timing out
  --help                          Show this message and exit.

Commands:
  config        Configure plusdeck.
  eject         Eject the tape
  expect        Wait for an expected state
  fast-forward  Fast-forward a tape
  pause         Pause the tape
  play          Play a tape
  rewind        Rewind a tape
  stop          Stop the tape
  subscribe     Subscribe to state changes

Jupyter Widgets

This library also includes some simple Jupyter widgets, under the plusdeck.jupyter namespace. These are ConfigEditor, for editing the CLI configuration file, and player, for spawning a simple player UI. To see these in action, check out the Player.ipynb file in the root of this project.

Development

I use uv for managing dependencies, but also compile requirements.txt and requirements_dev.txt files that one can use instead. I also use just for task running, but if you don't have it installed you can run the commands manually.

This library has somewhat comprehensive unit test coverage through pytest. Additionally, it has an interactive integration test suite, using a bespoke test framework, which can be run with just integration.

Documentation

Other documentation is in ./docs.

Changelog

See CHANGELOG.md.

License

MIT, see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plusdeck-1.0.0.tar.gz (96.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

plusdeck-1.0.0-py3-none-any.whl (14.6 kB view details)

Uploaded Python 3

File details

Details for the file plusdeck-1.0.0.tar.gz.

File metadata

  • Download URL: plusdeck-1.0.0.tar.gz
  • Upload date:
  • Size: 96.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.2

File hashes

Hashes for plusdeck-1.0.0.tar.gz
Algorithm Hash digest
SHA256 c1f4cfeeb392545aeff1684abc7786abfcc1f44e94c8515d9b897aed339df44b
MD5 7ca305391584f8e7ca71932d12ff02da
BLAKE2b-256 b456c14a03e227bc86fa5f72b4ade76d5722d50f98c700347b37ef829c6ca913

See more details on using hashes here.

File details

Details for the file plusdeck-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: plusdeck-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 14.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.2

File hashes

Hashes for plusdeck-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 84855e07fb8258167466104ee7ad87f83f61f0805a5a411d1995a8d27aa07462
MD5 7ad12a54554c6cc264aaba7e24ab8bf9
BLAKE2b-256 94fde433d2df4c16b686aa496a31200186880edefdadc785306ccf8cd1048f57

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page