{"id":21150852,"url":"https://github.com/cedargrovestudios/circuitpython_punkconsole","last_synced_at":"2026-04-12T23:56:24.508Z","repository":{"id":139500750,"uuid":"551778771","full_name":"CedarGroveStudios/CircuitPython_PunkConsole","owner":"CedarGroveStudios","description":"A CircuitPython helper class to emulate the Atari Punk Console.","archived":false,"fork":false,"pushed_at":"2023-03-02T04:27:29.000Z","size":4999,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-02T04:56:07.041Z","etag":null,"topics":["atari-punk-console","circuitpython","circuitpython-community-bundle","music"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CedarGroveStudios.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-15T04:26:06.000Z","updated_at":"2025-07-11T03:41:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"7bdb3fba-314a-465c-970d-3bcb0fd3b509","html_url":"https://github.com/CedarGroveStudios/CircuitPython_PunkConsole","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/CedarGroveStudios/CircuitPython_PunkConsole","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CedarGroveStudios%2FCircuitPython_PunkConsole","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CedarGroveStudios%2FCircuitPython_PunkConsole/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CedarGroveStudios%2FCircuitPython_PunkConsole/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CedarGroveStudios%2FCircuitPython_PunkConsole/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CedarGroveStudios","download_url":"https://codeload.github.com/CedarGroveStudios/CircuitPython_PunkConsole/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CedarGroveStudios%2FCircuitPython_PunkConsole/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31734350,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-12T22:19:12.206Z","status":"ssl_error","status_checked_at":"2026-04-12T22:18:33.088Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atari-punk-console","circuitpython","circuitpython-community-bundle","music"],"created_at":"2024-11-20T10:09:00.672Z","updated_at":"2026-04-12T23:56:24.488Z","avatar_url":"https://github.com/CedarGroveStudios.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Introduction\n============\n\n\n\n\n.. image:: https://img.shields.io/discord/327254708534116352.svg\n    :target: https://adafru.it/discord\n    :alt: Discord\n\n\n.. image:: https://github.com/CedarGroveStudios/CircuitPython_PunkConsole/workflows/Build%20CI/badge.svg\n    :target: https://github.com/CedarGroveStudios/CircuitPython_PunkConsole/actions\n    :alt: Build Status\n\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://github.com/psf/black\n    :alt: Code Style: Black\n\nA CircuitPython-based Atari Punk Console emulation helper class based on the\n\"Stepped Tone Generator\" circuit, \"Engineer's Mini-Notebook: 555 Circuits\",\nForrest M. Mims III (1984).\n\n\nDependencies\n=============\nThis driver depends on:\n\n* `Adafruit CircuitPython \u003chttps://github.com/adafruit/circuitpython\u003e`_\n\nPlease ensure all dependencies are available on the CircuitPython filesystem.\nThis is easily achieved by downloading\n`the Adafruit library and driver bundle \u003chttps://circuitpython.org/libraries\u003e`_\nor individual libraries can be installed using\n`circup \u003chttps://github.com/adafruit/circup\u003e`_.\n\nInstalling to a Connected CircuitPython Device with Circup\n==========================================================\n\nMake sure that you have ``circup`` installed in your Python environment.\nInstall it with the following command if necessary:\n\n.. code-block:: shell\n\n    pip3 install circup\n\nWith ``circup`` installed and your CircuitPython device connected use the\nfollowing command to install:\n\n.. code-block:: shell\n\n    circup install cedargrove_punkconsole\n\nOr the following command to update an existing version:\n\n.. code-block:: shell\n\n    circup update\n\nUsage Example\n=============\n\n.. code-block:: python\n\n    import board\n    import analogio\n    import pwmio\n    from simpleio import map_range\n    from cedargrove_punkconsole import PunkConsole\n\n    # instantiate a PunkConsole output on pin A1 (PWM-capable)\n    punk_console = PunkConsole(board.A1, mute=False)\n\n    # define the two potentiometer inputs\n    f_in = analogio.AnalogIn(board.A2)  # Oscillator Frequency\n    pw_in = analogio.AnalogIn(board.A3)  # One-Shot Pulse Width\n\n    while True:\n        # read the inputs, map to practical audio ranges, send to PunkConsole instance\n        #   oscillator frequency range: 3Hz to 3kHz\n        #   one-shot pulse width range: 0.5ms to 5ms\n        punk_console.frequency = map_range(f_in.value, 0, 65535, 3, 3000)\n        punk_console.pulse_width_ms = map_range(pw_in.value, 0, 65535, 0.5, 5.0)\n\nDocumentation\n=============\nAPI documentation for this library can be found in `PunkConsole_API \u003chttps://github.com/CedarGroveStudios/CircuitPython_PunkConsole/blob/main/media/pseudo_readthedocs_cedargrove_punkconsole.pdf\u003e`_.\n\n\n.. image:: https://github.com/CedarGroveStudios/CircuitPython_PunkConsole/blob/main/media/Stereo_Punk_Console_test.png\n\nThe CedarGrove PunkConsole emulates an astable square-wave oscillator and\nsynchronized non-retriggerable one-shot monostable multivibrator to create\nthe classic stepped-tone generator sound of the Atari Punk Console. As with\nthe original circuit, the oscillator frequency and one-shot pulse width are\nthe input parameters. Instantiation of the Punk Console class will start the\noutput waveform based on the input parameters and enable the output signal\nif `mute=False`. If no input parameters are provided, the output signal\nwill be disabled regardless of the mute value. Once instantiated, the class\nis controlled by the `frequency`, `pulse_width_ms`, and `mute` properties.\n\nThis version of the emulator works only with PWM-capable output pins.\n\nDepending on the timer and PWM capabilities of the host MPU board, the\nemulator can easily outperform the original analog circuit. Oscillator\nfrequency is only limited by the MPU's PWM duty cycle and frequency\nparameters, which may create output signals well above the practical audio\nhearing range. Therefore, it is recommended that one-shot pulse width input\nbe limited to the range of 0.5ms and 5ms and that the oscillator frequency\ninput range be between 3Hz and 3kHz -- although experimentation is\nencouraged!\n\nThe repo contains three examples, a simple single-channel console, an\nannoying stereo noisemaker, and a note table driven sequencer. For the first\ntwo examples, input is provided by potentiometers attached to\ntwo analog input pins. The sequencer is controlled by an internal list of\nnotes that select the oscillator frequency; pulse width is potentiometer\ncontrolled.\n\n- Minimum and maximum input ranges (may be further limited by the MPU):\n    - pulse_width: 0.05ms to  5000ms\n    - frequency:      1Hz to \u003e4MHz\n\n- Practical input ranges for audio (empirically determined):\n    - pulse_width:  0.5ms to 5ms\n    - frequency:      3Hz to 3kHz\n\nThe CedarGrove Punk Console algorithm uses PWM frequency and duty cycle\nparameters to build the output waveform. The PWM output frequency is an\ninteger multiple of the oscillator frequency input compared to the one-shot\npulse width input:\n\n``pwm_freq = freq_in / (int((pulse_width) * freq_in) + 1)``\n\nThe PWM output duty cycle is calculated after the PWM output frequency is\ndetermined. The PWM output duty cycle is the ratio of the one-shot pulse\nwidth and the wavelength of the PWM output frequency:\n\n``pwm_duty_cycle = pulse_width * pwm_freq``\n\n\nPlanned updates:\n\nFor non-PWM analog output, use ``audiocore`` with a waveform sample in the\n``RawSample`` binary array, similar to the ``simpleio.tone()`` helper. The output\nwaveform's duty cycle will be adjusted by altering the contents of the array,\nperhaps with `ulab` to improve code execution time. The\n``audiocore.RawSample.sample_rate`` frequency is expected to be directly\nproportional to the original algorithm's PWM frequency output value, calculated\nfrom the ``sample_rate`` divided by the length of the ``audiocore.RawSample`` array\n(number of samples).\n\nMIDI control: A version that uses USB and/or UART MIDI is in the queue. Note\nthat the ``PunkConsole.mute`` property could be used for note-on and note-off.\n``note_in_example.py`` shows how muting can be used for individual notes.\n\nCV control: A Eurorack version was discussed, it's just a bit lower on the\nto-do list, that's all. But you know, the first two examples use analog inputs\n(0 to +3.3 volts) for frequency and pulse width control. Just sayin'.\n\n\n.. image:: https://github.com/CedarGroveStudios/CircuitPython_PunkConsole/blob/main/media/CG_PunkConsole_04.jpeg\n\n.. image:: https://github.com/CedarGroveStudios/CircuitPython_PunkConsole/blob/main/media/CG_PunkConsole_01.jpeg\n\n.. image:: https://github.com/CedarGroveStudios/CircuitPython_PunkConsole/blob/main/media/CG_PunkConsole_02.jpeg\n\n.. image:: https://github.com/CedarGroveStudios/CircuitPython_PunkConsole/blob/main/media/CG_PunkConsole_03.jpeg\n\n\nFor information on building library documentation, please check out\n`this guide \u003chttps://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1\u003e`_.\n\nContributing\n============\n\nContributions are welcome! Please read our `Code of Conduct\n\u003chttps://github.com/CedarGroveStudios/Cedargrove_CircuitPython_PunkConsole/blob/HEAD/CODE_OF_CONDUCT.md\u003e`_\nbefore contributing to help this project stay welcoming.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcedargrovestudios%2Fcircuitpython_punkconsole","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcedargrovestudios%2Fcircuitpython_punkconsole","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcedargrovestudios%2Fcircuitpython_punkconsole/lists"}