Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 04:30 19 Feb 2026 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : PicoMite V6.02.01 betas

     Page 3 of 3    
Author Message
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 8564
Posted: 07:54am 16 Feb 2026
Copy link to clipboard 
Print this post

GP30-GP36 are linked to GP40-GP46 via resistors. GP30-GP36 are currently set to 1 to provide pull up (or they can provide pull down) to GP40-GP46. This allows the whole controller port to be reconfigured as active low or high or ADC for each pin individually in software.

If GP32-GP36 aren't being selected for output when using PORT it would certainly tie in with PORT(GP30,7) returning &h03 from the control register if the output register is partially controlled. If the output latches are disabled then GP40-GP46 may well return &h00.

I know it's not a hardware problem as I can set GP30-GP36 individually using PIN() and read GP40-GP46 individually, testing them as active low inputs.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 5703
Posted: 04:55pm 16 Feb 2026
Copy link to clipboard 
Print this post

Mick, Try 60003 or 60100 from geoffs archive.
You used this pga before, right?
Never noticed this?

Volhout
Edited 2026-02-17 02:57 by Volhout
PicomiteVGA PETSCII ROBOTS
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 8564
Posted: 05:47pm 16 Feb 2026
Copy link to clipboard 
Print this post

I'll try some other versions. I've been a bit busy attempting to test other bits. :)

No, I don't think I've ever used PORT on any RP2350 before. It's one of those commands that I haven't used much at all really, although I definitely did a couple of times on the RP2040.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10965
Posted: 10:56pm 16 Feb 2026
Copy link to clipboard 
Print this post

Been travelling - will check tomorrow
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10965
Posted: 08:43am 17 Feb 2026
Copy link to clipboard 
Print this post

Mick, I assume you are using the non-USB version? If so please try the attached and report.

PicoMite.zip
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 8564
Posted: 08:58am 17 Feb 2026
Copy link to clipboard 
Print this post

Yes, it's non-USB. Will do, thanks.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 8564
Posted: 10:30am 17 Feb 2026
Copy link to clipboard 
Print this post

Thanks, Peter. That seems to have got PORT working nicely again. :)
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10965
Posted: 10:35am 17 Feb 2026
Copy link to clipboard 
Print this post

Not again - ever when using pins > GP31

Here is the fix

Before
setmask |= (1 << PinDef[pin].GPno);

After
setmask |= (1ll << PinDef[pin].GPno);
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10965
Posted: 11:18am 17 Feb 2026
Copy link to clipboard 
Print this post

V6.02.01b3

PicoMiteRP2040V6.02.01b3.zip

All versions
Fixes bug in using function calls as parameters to functions or subroutines
Corrects behaviour when the A: drive is formatted when the current directory is not at root level

RP2350 only
Fixes bug in PORT commands and functions when pins > GP31 are used on the RP2350B
at the top level
Allows blank lines in TYPE definitions
Implements FRAME command for writing a text based GUI

FRAME_User_Manual.pdf
 
bfwolf
Senior Member

Joined: 03/01/2025
Location: Germany
Posts: 166
Posted: 12:27pm 17 Feb 2026
Copy link to clipboard 
Print this post

  matherp said  Not again - ever when using pins > GP31


"Everyday the Groundhog greeting..." - Literally translated from the German proverb "Und täglich grüßt das Murmeltier..."  
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 5703
Posted: 01:51pm 17 Feb 2026
Copy link to clipboard 
Print this post

Hi Peter,

Is there a reason why in the FRAME user manual some names of the 16 colors are changed, and what is the impact on commands as RGB(Myrtle), RGB(Cerulean).
Are the names interchangeable?

Volhout
PicomiteVGA PETSCII ROBOTS
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10965
Posted: 02:09pm 17 Feb 2026
Copy link to clipboard 
Print this post

Just the manual wrong, I'll update it before the release
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10965
Posted: 05:14pm 17 Feb 2026
Copy link to clipboard 
Print this post

V6.02.01b4

PicoMiteV6.02.01b4.zip

RP2040 - no changes

RP2350
Tweaks to flash and param timings to improve reliability.
The PGA2350 will run for me at 384MHz with PSRAM enabled
The Pico2 will run at 429MHz
New command:
AUDIO SAMPLE implements ADRS shaping
  Quote  # PLAY SAMPLE Command User Manual

## Overview

The `PLAY SAMPLE` command plays back a single-cycle waveform stored in integer arrays with a software-generated ADSR (Attack, Decay, Sustain, Release) amplitude envelope. This enables synthesiser-style sound generation where the timbre is defined by the waveform shape and the dynamics are controlled by envelope parameters.

The waveform is looped continuously at the requested frequency using a phase accumulator, while the ADSR envelope shapes the amplitude over time. This is distinct from `PLAY ARRAY` which plays a pre-recorded buffer once at a given sample rate.

**Note:** This command is only available on RP2350-based PicoMite builds.

## Syntax

### Start Playback
```basic
PLAY SAMPLE left%(), right%(), freq, attack, decay, sustain, release
PLAY SAMPLE left%(), right%(), freq, attack, decay, sustain, release, interrupt
```

### Trigger Release Phase
```basic
PLAY RELEASE
```

### Stop Immediately
```basic
PLAY STOP
```

### Pause / Resume
```basic
PLAY PAUSE
PLAY RESUME
```

## Parameters

| Parameter | Description |
| :--- | :--- |
| `left%()` | Integer array containing one cycle of the left-channel waveform. Values should be in the range −32000 to +32000 (signed 16-bit). |
| `right%()` | Integer array containing one cycle of the right-channel waveform. Must be the same size as `left%()`. For mono output, use the same data in both arrays. |
| `freq` | Playback frequency in Hz (10.0 to 48000.0). This is the pitch of the output tone, not the sample rate. The waveform cycle is played back at this frequency regardless of the number of samples in the array. |
| `attack` | Attack time in milliseconds (0 to 30000). Time for the envelope to ramp from silence to full volume. 0 = instant full volume. |
| `decay` | Decay time in milliseconds (0 to 30000). Time for the envelope to fall from full volume to the sustain level. 0 = instant drop to sustain level. |
| `sustain` | Sustain level as a percentage (0 to 100). The steady-state volume held after the decay phase completes. 0 = note dies after decay (no sustain). |
| `release` | Release time in milliseconds (0 to 30000). Time for the envelope to fade from the sustain level to silence after `PLAY RELEASE` is issued. 0 = instant silence on release. |
| `interrupt` | Optional. A label (subroutine) to call when the release phase completes and the note has finished. The subroutine must end with `IRETURN`. |

## ADSR Envelope

The ADSR envelope controls how the volume of the note changes over time:

```
Volume
 ^
 |    /\
 |   /  \
 |  /    \___________
 | /      Sustain    \
 |/                   \
 +------+---+---------+----> Time
 Attack Decay         Release
        ^             ^
        |             |
   PLAY SAMPLE    PLAY RELEASE
```

1. **Attack**: When `PLAY SAMPLE` is executed, the volume ramps linearly from 0 to maximum over the attack time.
2. **Decay**: The volume falls from maximum to the sustain level over the decay time.
3. **Sustain**: The volume holds at the sustain level indefinitely until `PLAY RELEASE` is issued.
4. **Release**: After `PLAY RELEASE`, the volume fades from the sustain level to silence over the release time. When complete, playback stops and the optional interrupt is triggered.

### Special Cases

- **Sustain = 0**: The note dies naturally after the decay phase without waiting for `PLAY RELEASE`. This is useful for plucked or percussive sounds.
- **Attack = 0**: The note starts at full volume instantly.
- **Release = 0**: The note stops instantly when `PLAY RELEASE` is issued.
- **All times = 0, Sustain = 100**: Produces a continuous tone at full volume (equivalent to an organ stop).

## Waveform Arrays

Each array holds exactly one cycle of the waveform. The number of elements determines the resolution of the waveform shape — more elements give a smoother waveform with fewer harmonics. Typical sizes are 64 to 1024 elements.

The firmware uses a phase accumulator to step through the waveform table at the correct rate for the requested pitch, so the array size does not affect the output frequency — only the tonal quality.

Sample values should be in the range −32000 to +32000. Values outside this range may cause clipping.

### Common Waveforms

**Sine wave** (pure tone, no harmonics):
```basic
Const N = 256
Dim Integer wave%(N - 1)
For i% = 0 To N - 1
 wave%(i%) = Int(Sin(2 * Pi * i% / N) * 32000)
Next i%
```

**Square wave** (odd harmonics, hollow sound):
```basic
Const N = 256
Dim Integer wave%(N - 1)
For i% = 0 To N - 1
 If i% < N / 2 Then wave%(i%) = 32000 Else wave%(i%) = -32000
Next i%
```

**Sawtooth wave** (all harmonics, bright/buzzy):
```basic
Const N = 256
Dim Integer wave%(N - 1)
For i% = 0 To N - 1
 wave%(i%) = Int((i% / N * 2 - 1) * 32000)
Next i%
```

**Triangle wave** (odd harmonics, softer than square):
```basic
Const N = 256
Dim Integer wave%(N - 1)
For i% = 0 To N - 1
 Local Float t = i% / N
 If t < 0.5 Then
   wave%(i%) = Int((4 * t - 1) * 32000)
 Else
   wave%(i%) = Int((3 - 4 * t) * 32000)
 EndIf
Next i%
```

## Restarting Playback

`PLAY SAMPLE` can be called while a sample is already playing. The current note is stopped cleanly and the new note begins immediately. This allows playing melodies by issuing successive `PLAY SAMPLE` commands with different frequencies without needing to call `PLAY STOP` or `PLAY RELEASE` between notes.

## Interaction with Other Audio Commands

- `PLAY SAMPLE` uses the same audio output hardware as `PLAY TONE`, `PLAY SOUND`, `PLAY WAV`, `PLAY ARRAY`, etc. Only one can be active at a time.
- Attempting to start `PLAY SAMPLE` while another audio mode is playing (other than a previous sample) will produce an error: `"Sound output in use for ..."`.
- `PLAY VOLUME` affects sample playback — the ADSR envelope is applied on top of the global volume setting.
- `PLAY STOP` immediately halts sample playback at any point.

## Examples

### Example 1: Simple Organ Tone

Play a sustained 440 Hz sine wave with a quick attack and gentle release:

```basic
Option Base 0
Const N = 256
Dim Integer L%(N-1), R%(N-1)

For i% = 0 To N-1
 L%(i%) = Int(Sin(2 * Pi * i% / N) * 32000)
 R%(i%) = L%(i%)
Next i%

Play Sample L%(), R%(), 440, 10, 50, 80, 200
Pause 2000
Play Release
Pause 300
```

### Example 2: Piano-Style Note

Fast attack, moderate decay to a low sustain level, then release:

```basic
Play Sample L%(), R%(), 262, 5, 300, 20, 500
Pause 2000
Play Release
Pause 600
```

### Example 3: Plucked String

Instant attack, fast decay to zero sustain — the note dies naturally without needing `PLAY RELEASE`:

```basic
Play Sample L%(), R%(), 523, 1, 400, 0, 100
Pause 600
```

### Example 4: Slow Pad

Gradual fade-in, high sustain, long release for an atmospheric pad sound:

```basic
Play Sample L%(), R%(), 330, 800, 200, 70, 1500
Pause 4000
Play Release
Pause 1600
```

### Example 5: Playing a Melody

Play notes in sequence by restarting `PLAY SAMPLE` at different frequencies. Use `PLAY RELEASE` between notes for articulation:

```basic
Option Base 0
Const N = 256
Dim Integer L%(N-1), R%(N-1)

' Build sine waveform
For i% = 0 To N-1
 L%(i%) = Int(Sin(2 * Pi * i% / N) * 32000)
 R%(i%) = L%(i%)
Next i%

' C major scale
Restore notes
For n% = 1 To 8
 Read f
 Play Sample L%(), R%(), f, 5, 150, 30, 200
 Pause 350
 Play Release
 Pause 250
Next n%
End

notes:
Data 261.6, 293.7, 329.6, 349.2, 392.0, 440.0, 493.9, 523.3
```

### Example 6: Using the Interrupt

Detect when a note finishes and set a flag:

```basic
Dim INTEGER playing% = 1

Play Sample L%(), R%(), 440, 5, 300, 20, 500, note_done
Pause 2000
Play Release

' Wait for note to finish
Do While playing% : Loop
Print "Note finished."
End

note_done:
 playing% = 0
 IReturn
```

## Technical Notes

- The output sample rate is fixed at 44,100 Hz (raised automatically if the requested frequency exceeds the Nyquist limit).
- The ADSR envelope uses 16.16 fixed-point arithmetic for smooth, click-free amplitude transitions.
- Each `PLAY SAMPLE` call allocates two 8 KB swing buffers for double-buffered output. These are freed when playback stops.
- The waveform arrays are read directly from MMBasic integer memory — they are not copied. Do not modify the arrays while playback is active.
- The `left%()` and `right%()` arrays must be one-dimensional integer arrays of the same size.

## Error Messages

| Error | Cause |
| :--- | :--- |
| `Sound output in use for ...` | Another audio mode is already playing. Use `PLAY STOP` first. |
| `Invalid frequency 10.0 - 48000.0` | The `freq` parameter is outside the allowed range. |
| `Not playing a sample` | `PLAY RELEASE` was issued but no sample is currently playing. |
| `No program running` | An interrupt label was specified but the command was run from the command prompt rather than within a program. |


example program
' ============================================================
' PLAY SAMPLE Demo - ADSR Envelope on a single-cycle waveform
' ============================================================
' This demo creates a single-cycle sine wave in an integer
' array, then plays it back using PLAY SAMPLE with Attack,
' Decay, Sustain and Release parameters.
'
' Syntax:
'   PLAY SAMPLE left%(), right%(), freq, attack, decay,
'               sustain, release [,interrupt]
'
'   left%(), right%() = single-cycle waveform arrays (INTEGER)
'   freq              = playback frequency in Hz (10 - 48000)
'   attack            = attack time in ms (0 - 30000)
'   decay             = decay time in ms (0 - 30000)
'   sustain           = sustain level 0 - 100 (percentage)
'   release           = release time in ms (0 - 30000)
'   interrupt         = optional label called when release ends
'
' PLAY RELEASE triggers the release phase.
' PLAY STOP   stops immediately.
' ============================================================
Option Base 0
Const CYCLE_LEN = 256       ' samples per single cycle
Const AMPLITUDE = 32000     ' peak amplitude (16-bit signed)
Dim INTEGER left%(CYCLE_LEN - 1)
Dim INTEGER right%(CYCLE_LEN - 1)
' --- Build a single-cycle sine wave ---
For i% = 0 To CYCLE_LEN - 1
 left%(i%)  = Int(Sin(2 * Pi * i% / CYCLE_LEN) * AMPLITUDE)
 right%(i%) = left%(i%)    ' mono: same on both channels
Next i%
' --- Example 0: Clean sine wave (no envelope shaping) ---
' Full volume, no decay, no release - just a pure tone.
' If this doesn't sound clean, the problem is in the core
' waveform playback, not the ADSR envelope.
Print "Playing clean 440 Hz sine for 2 seconds..."
Print "  Attack=0ms  Decay=0ms  Sustain=100%  Release=0ms"
Play Sample left%(), right%(), 440, 0, 0, 100, 0
Pause 2000
Play Stop
Print "Done."
Print
' --- Example 0b: Clean sine at 880 Hz (high note check) ---
Print "Playing clean 880 Hz sine for 2 seconds..."
Print "  Attack=0ms  Decay=0ms  Sustain=100%  Release=0ms"
Play Sample left%(), right%(), 880, 0, 0, 100, 0
Pause 2000
Play Stop
Print "Done."
Print
' --- Example 1: Organ-style (fast attack, long sustain) ---
Print "Playing organ tone at 440 Hz..."
Print "  Attack=10ms  Decay=50ms  Sustain=80%  Release=200ms"
Play Sample left%(), right%(), 440, 10, 50, 80, 200, done
' Hold the note for 2 seconds then release
Pause 2000
Play Release
' Wait for release to finish
Do While SamplePlaying% : Loop
Print "Done."
Print
' --- Example 2: Piano-style (fast attack, moderate decay, low sustain) ---
Print "Playing piano tone at 262 Hz (middle C)..."
Print "  Attack=5ms  Decay=300ms  Sustain=20%  Release=500ms"
Play Sample left%(), right%(), 262, 5, 300, 20, 500
Pause 3000
Play Release
Pause 600
Print "Done."
Print
' --- Example 3: Pad-style (slow attack, high sustain) ---
Print "Playing pad tone at 330 Hz..."
Print "  Attack=800ms  Decay=200ms  Sustain=70%  Release=1500ms"
Play Sample left%(), right%(), 330, 800, 200, 70, 1500
Pause 4000
Play Release
Pause 1600
Print "Done."
Print
' --- Example 4: Pluck-style (instant attack, fast decay, no sustain) ---
Print "Playing pluck at 523 Hz..."
Print "  Attack=1ms  Decay=400ms  Sustain=0%  Release=100ms"
Play Sample left%(), right%(), 523, 1, 400, 0, 100
' With sustain=0 the note dies naturally after decay
Pause 600
Print "Done."
Print
' --- Example 5: Chromatic scale with consistent envelope ---
Print "Chromatic scale with string envelope..."
Restore scale_data
For note% = 1 To 13
 Read freq
 Print "  Note"; note%; " freq="; freq; "Hz"
 Play Sample left%(), right%(), freq, 20, 100, 60, 300
 Pause 400
 Play Release
 Pause 100
Next note%
Print "Scale complete."
Print
' --- Example 6: Twinkle Twinkle Little Star (piano) ---
Print "Playing Twinkle Twinkle Little Star..."
Restore twinkle_data
For note% = 1 To 42
 Read nfreq, dur
 If nfreq = 0 Then
   ' Rest
   Pause dur
 Else
   Print "  freq="; nfreq; "Hz  dur="; dur; "ms"
   Play Sample left%(), right%(), nfreq, 5, 150, 30, 100
   Pause dur
   Play Release
   Pause 100
 EndIf
Next note%
Print "Tune complete."
End
done:
 ' Interrupt handler for end of release
 SamplePlaying% = 0
 IReturn
' Frequencies for one chromatic octave (A4 to A5)
scale_data:
Data 440.0, 466.2, 493.9, 523.3, 554.4, 587.3, 622.3
Data 659.3, 698.5, 740.0, 784.0, 830.6, 880.0
' Twinkle Twinkle Little Star - C major (traditional, public domain)
' Each pair: frequency (Hz), duration (ms)
' C=261.6 D=293.7 E=329.6 F=349.2 G=392.0 A=440.0
' Line 1: C C G G A A G-
twinkle_data:
Data 261.6, 350, 261.6, 350, 392.0, 350, 392.0, 350
Data 440.0, 350, 440.0, 350, 392.0, 700
' Line 2: F F E E D D C-
Data 349.2, 350, 349.2, 350, 329.6, 350, 329.6, 350
Data 293.7, 350, 293.7, 350, 261.6, 700
' Line 3: G G F F E E D-
Data 392.0, 350, 392.0, 350, 349.2, 350, 349.2, 350
Data 329.6, 350, 329.6, 350, 293.7, 700
' Line 4: G G F F E E D-
Data 392.0, 350, 392.0, 350, 349.2, 350, 349.2, 350
Data 329.6, 350, 329.6, 350, 293.7, 700
' Line 5: C C G G A A G-
Data 261.6, 350, 261.6, 350, 392.0, 350, 392.0, 350
Data 440.0, 350, 440.0, 350, 392.0, 700
' Line 6: F F E E D D C-
Data 349.2, 350, 349.2, 350, 329.6, 350, 329.6, 350
Data 293.7, 350, 293.7, 350, 261.6, 700
 
bfwolf
Senior Member

Joined: 03/01/2025
Location: Germany
Posts: 166
Posted: 05:31pm 17 Feb 2026
Copy link to clipboard 
Print this post

  matherp said  V6.02.01b4

...

New command:
AUDIO SAMPLE implements ADRS shaping
  Quote  # PLAY SAMPLE Command User Manual
...



Are you currently building a YAMAHA DX7 clone, or are you planning to?
 
homa

Guru

Joined: 05/11/2021
Location: Germany
Posts: 539
Posted: 05:35pm 17 Feb 2026
Copy link to clipboard 
Print this post

Peter
You're making me crazy with joy :-)
PLAY SAMPLE is a dream.

PS: Did you see my question in the other thread about the graphics for your Raycaster demo? Can you upload them here? Thanks!

Matthias
 
     Page 3 of 3    
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2026