Menu
JAQForum Ver 19.10.27

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

   Page 3 of 8    
Posted: 07:54am
16 Feb 2026
Copy link to clipboard
Mixtel90
Guru


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.
 
Posted: 04:55pm
16 Feb 2026
Copy link to clipboard
Volhout
Guru

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
 
Posted: 05:47pm
16 Feb 2026
Copy link to clipboard
Mixtel90
Guru


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.
 
Posted: 10:56pm
16 Feb 2026
Copy link to clipboard
matherp
Guru

Been travelling - will check tomorrow
 
Posted: 08:43am
17 Feb 2026
Copy link to clipboard
matherp
Guru

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

PicoMite.zip
 
Posted: 08:58am
17 Feb 2026
Copy link to clipboard
Mixtel90
Guru


Yes, it's non-USB. Will do, thanks.
 
Posted: 10:30am
17 Feb 2026
Copy link to clipboard
Mixtel90
Guru


Thanks, Peter. That seems to have got PORT working nicely again. :)
 
Posted: 10:35am
17 Feb 2026
Copy link to clipboard
matherp
Guru

Not again - ever when using pins > GP31

Here is the fix

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

After
setmask |= (1ll << PinDef[pin].GPno);
 
Posted: 11:18am
17 Feb 2026
Copy link to clipboard
matherp
Guru

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
 
Posted: 12:27pm
17 Feb 2026
Copy link to clipboard
bfwolf
Senior Member

  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..."  
 
Posted: 01:51pm
17 Feb 2026
Copy link to clipboard
Volhout
Guru

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
 
Posted: 02:09pm
17 Feb 2026
Copy link to clipboard
matherp
Guru

Just the manual wrong, I'll update it before the release
 
Posted: 05:14pm
17 Feb 2026
Copy link to clipboard
matherp
Guru

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
 
Posted: 05:31pm
17 Feb 2026
Copy link to clipboard
bfwolf
Senior Member

  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?
 
Posted: 05:35pm
17 Feb 2026
Copy link to clipboard
homa
Guru


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
 
Posted: 08:14pm
18 Feb 2026
Copy link to clipboard
Bleep
Guru

Hi Peter,
Just loaded B4 onto a Pico 2 2350 LCD and it's runing flat out at 420MHz with no apparent problems.
 
Posted: 09:09pm
18 Feb 2026
Copy link to clipboard
JohnS
Guru

420MHz!!

John
 
Posted: 11:15pm
18 Feb 2026
Copy link to clipboard
JanVolk
Guru

A few things I noticed with V6.02.01b4.

When I use Input$() in the editor, it changes to Input $() after saving.

When I play an MP3 with quick transitions, some passages become distorted.
I thought about setting the frequency higher, but that doesn't work anymore. I've tried various frequencies.
Error message:
> option cpuspeed 200000
[39] CSub
Error: Invalid identifier

PicoMite MMBasic RP2350A V6.02.01b4
OPTION SYSTEM I2C GP20, GP21
OPTION FLASH SIZE 4194304
OPTION COLOURCODE ON
OPTION HEARTBEAT OFF
OPTION PICO OFF
OPTION CPUSPEED (KHz) 200000
OPTION DISPLAY 50, 100
OPTION SD CARD GP22, GP6, GP7, GP4
OPTION AUDIO I2S GP2, GP5, ON PWM CHANNEL 11
OPTION RTC AUTO ENABLE
OPTION MODBUFF ENABLE 192
OPTION F1 help           'The function keys have been modified with the necessary       
OPTION F5 list commands  '"+" and chr$(13) functions.
OPTION F6 list functions
OPTION F7 list pins
OPTION F8 option list
OPTION F9 flash run 1 'This starts the minifm_RC2.bas

Note: The Raspberry Pi Pico 2W is mounted on an Olimex board with female connectors, omitting the HDMI on the Olimex and the Wi-Fi module on the Raspberry Pi Pico 2W PCB. A DS3231+EEPROM is also mounted under the Olimex PCB.
The I2S DAC PCM5102A from the manual fits exactly upside down under the PicoMate, and the LINE OUT connector is still easily accessible. I did insert a template to prevent short-circuits, and the markings indicate the correct pinouts.

Jan.
Edited 2026-02-19 09:21 by JanVolk
 
Posted: 08:36am
19 Feb 2026
Copy link to clipboard
matherp
Guru

Are you using input$ as a variable name? If so that is the issue, it is conflicting with the command input
 
Posted: 05:51pm
19 Feb 2026
Copy link to clipboard
JanVolk
Guru

Peter,

Thanks for the reply.
The first problem came to light in the help file.
Your reasoning is indeed correct.

> help input
Input ["prompt$";] var1 [,var2[,var3[,etc.]]]
Input #nbr, list of variables

' Input$(nbr, [#]fnbr)

The second problem might have arisen earlier when overloading the A: drive with an .mp3 file?
Only a report that the A: drive was full and the .mp3 was 0 KB and deleted with kill. Perhaps something broke after that?
Tried again today, first with Clear_Flash_RP2350.uf2 and an MP3 test at 200 MHz with the same result.
Then I set the CPU speed to 300 MHz and the problem disappeared. Fast MP3 transitions now play correctly.

> option list
PicoMite MMBasic RP2350A V6.02.01b4
OPTION SYSTEM I2C GP20,GP21
OPTION FLASH SIZE 4194304
OPTION COLOURCODE ON
OPTION CPUSPEED (KHz) 300000
OPTION DISPLAY 50, 100
OPTION SDCARD GP22, GP6, GP7, GP4
OPTION AUDIO I2S GP2,GP5', ON PWM CHANNEL 11
OPTION RTC AUTO ENABLE
OPTION MODBUFF ENABLE  192
OPTION F1 help
OPTION F5 list commands
OPTION F6 list functions
OPTION F7 list pins
OPTION F8 option list
OPTION F9 flash run 1

Have a nice day,

Jan.
 
   Page 3 of 8    
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2026