Skip to content

Commit

Permalink
Modifications for Circle 45
Browse files Browse the repository at this point in the history
* Support USB sound cards on Raspberry Pi 4
* Use separate Circle sound library
* Allow to use system option USE_USB_FIQ (non-default)
* Update README
  • Loading branch information
rsta2 committed Dec 1, 2022
1 parent 5486bf5 commit 29aa449
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 5 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ MiniSynth Pi is a polyphonic virtual analog audio synthesizer, running bare meta

You have to attach an USB MIDI keyboard controller (which supports the USB Audio Class MIDI specification) or an USB PC keyboard to your Raspberry Pi to play on it. Alternatively you can feed serial MIDI data (at 31250 Bps) into GPIO15 (Broadcom numbering). Normally you will need some external circuit to be able to attach a device with serial MIDI interface.

The audio signal is normally available on the 3.5mm headphones jack (I2S usage see below). Thus Raspberry Pi models without headphones jack (e.g. Raspberry Pi Zero) are not supported. The graphical user interface (GUI) of MiniSynth Pi can be controlled using a standard USB mouse, the official Raspberry Pi touch screen or an USB HID-class touch screen in digitizer mode.
The audio signal is normally available on the 3.5mm headphones jack (I2S and USB usage see below). Thus Raspberry Pi models without headphones jack (e.g. Raspberry Pi Zero) are not supported. The graphical user interface (GUI) of MiniSynth Pi can be controlled using a standard USB mouse, the official Raspberry Pi touch screen or an USB HID-class touch screen in digitizer mode.

This version of MiniSynth Pi can be configured, so that it can be used with an external I2S interface. The audio signal is then available via this interface. MiniSynth Pi has been tested with the following I2S interfaces:

Expand All @@ -24,6 +24,8 @@ This version of MiniSynth Pi can be configured, so that it can be used with an e

Other I2S interfaces with these DACs may be compatible too. The I2C slave address of the DAC is auto-probed (0x4C, 0x4D or 0x1A).

On the Raspberry Pi 4 and 400 also external USB sound cards can be used.

Please note that the included reverb effect module is experimental, because it generates some noise, when no note is played. Just leave the reverb volume (wet/dry ratio) at 0% to eliminate it, if it disturbs.

Getting
Expand Down Expand Up @@ -77,6 +79,10 @@ If you want to use an I2S interface, you have to modify to file *cmdline.txt* on

sounddev=sndi2s

If you want to use an USB sound card (on the Raspberry Pi 4 and 400 only), you have to attach it, before the system is started. The file *cmdline.txt* must contain the following option:

sounddev=sndusb

Put the SD card into the card reader of your Raspberry Pi.

USB Touch Screen Calibration
Expand All @@ -102,7 +108,7 @@ Before powering on your Raspberry Pi, the following devices have to be attached:
* HDMI display (1920x1080 pixels max.)
* USB MIDI keyboard controller, USB PC keyboard or device with serial MIDI interface (at GPIO15, requires external circuit)
* Standard USB mouse (if touch screen is not used)
* Headphones or amplifier (on the 3.5mm jack or via external I2S interface)
* Headphones or amplifier (on the 3.5mm jack or via external I2S interface or USB sound card)

MiniSynth Pi starts in about four seconds. It is controlled using the following GUI (*MAIN* tab):

Expand Down
1 change: 1 addition & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ LIBS = $(CIRCLEHOME)/addon/lvgl/liblvgl.a \
$(CIRCLEHOME)/lib/usb/libusb.a \
$(CIRCLEHOME)/lib/input/libinput.a \
$(CIRCLEHOME)/lib/fs/libfs.a \
$(CIRCLEHOME)/lib/sound/libsound.a \
$(CIRCLEHOME)/lib/libcircle.a

include $(CIRCLEHOME)/app/Rules.mk
Expand Down
6 changes: 6 additions & 0 deletions src/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ boolean CKernel::Initialize (void)
m_pSynthesizer = new CMiniSynthesizerI2S (&m_Config, &m_Interrupt,
&m_I2CMaster);
}
#if RASPPI >= 4
else if (strcmp (pSoundDevice, "sndusb") == 0)
{
m_pSynthesizer = new CMiniSynthesizerUSB (&m_Config, &m_Interrupt);
}
#endif
else
{
m_pSynthesizer = new CMiniSynthesizerPWM (&m_Config, &m_Interrupt);
Expand Down
90 changes: 90 additions & 0 deletions src/minisynth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,93 @@ unsigned CMiniSynthesizerI2S::GetChunk (u32 *pBuffer, unsigned nChunkSize)

return nResult;
}

//// USB //////////////////////////////////////////////////////////////////////

#if RASPPI >= 4

CMiniSynthesizerUSB::CMiniSynthesizerUSB (CSynthConfig *pConfig,
CInterruptSystem *pInterrupt)
: CMiniSynthesizer (pConfig, pInterrupt),
CUSBSoundBaseDevice (SAMPLE_RATE),
m_nMinLevel (GetRangeMin ()+1),
m_nMaxLevel (GetRangeMax ()-1),
m_bChannelsSwapped (AreChannelsSwapped ())
{
}

boolean CMiniSynthesizerUSB::Start (void)
{
return CUSBSoundBaseDevice::Start ();
}

boolean CMiniSynthesizerUSB::IsActive (void)
{
return CUSBSoundBaseDevice::IsActive ();
}

unsigned CMiniSynthesizerUSB::GetChunk (s16 *pBuffer, unsigned nChunkSize)
{
#ifdef SHOW_STATUS
unsigned nTicks = CTimer::GetClockTicks ();
#endif

GlobalLock ();

unsigned nResult = nChunkSize;

float fVolumeLevel = m_fVolume * m_nMaxLevel;

for (; nChunkSize > 0; nChunkSize -= 2) // fill the whole buffer
{
m_VoiceManager.NextSample ();

float fLevelLeft = m_VoiceManager.GetOutputLevelLeft ();
int nLevelLeft = (int) (fLevelLeft*fVolumeLevel);
if (nLevelLeft > (int) m_nMaxLevel)
{
nLevelLeft = m_nMaxLevel;
}
else if (nLevelLeft < m_nMinLevel)
{
nLevelLeft = m_nMinLevel;
}

float fLevelRight = m_VoiceManager.GetOutputLevelRight ();
int nLevelRight = (int) (fLevelRight*fVolumeLevel);
if (nLevelRight > (int) m_nMaxLevel)
{
nLevelRight = m_nMaxLevel;
}
else if (nLevelRight < m_nMinLevel)
{
nLevelRight = m_nMinLevel;
}

// for 2 stereo channels
if (!m_bChannelsSwapped)
{
*pBuffer++ = (s16) nLevelLeft;
*pBuffer++ = (s16) nLevelRight;
}
else
{
*pBuffer++ = (s16) nLevelRight;
*pBuffer++ = (s16) nLevelLeft;
}
}

#ifdef SHOW_STATUS
nTicks = CTimer::GetClockTicks () - nTicks;
if (nTicks > m_nMaxDelayTicks)
{
m_nMaxDelayTicks = nTicks;
}
#endif

GlobalUnlock ();

return nResult;
}

#endif
28 changes: 26 additions & 2 deletions src/minisynth.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@

#include <circle/interrupt.h>
#include <circle/i2cmaster.h>
#include <circle/pwmsoundbasedevice.h>
#include <circle/i2ssoundbasedevice.h>
#include <circle/sound/pwmsoundbasedevice.h>
#include <circle/sound/i2ssoundbasedevice.h>
#include <circle/sound/usbsoundbasedevice.h>
#include <circle/string.h>
#include <circle/types.h>
#include "synthconfig.h"
Expand Down Expand Up @@ -134,4 +135,27 @@ class CMiniSynthesizerI2S : public CMiniSynthesizer, public CI2SSoundBaseDevice
boolean m_bChannelsSwapped;
};

//// USB //////////////////////////////////////////////////////////////////////

#if RASPPI >= 4

class CMiniSynthesizerUSB : public CMiniSynthesizer, public CUSBSoundBaseDevice
{
public:
CMiniSynthesizerUSB (CSynthConfig *pConfig, CInterruptSystem *pInterrupt);

boolean Start (void);
boolean IsActive (void);

private:
unsigned GetChunk (s16 *pBuffer, unsigned nChunkSize);

private:
int m_nMinLevel;
int m_nMaxLevel;
boolean m_bChannelsSwapped;
};

#endif

#endif
7 changes: 6 additions & 1 deletion src/serialmididevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// serialmididevice.cpp
//
// MiniSynth Pi - A virtual analogue synthesizer for Raspberry Pi
// Copyright (C) 2017-2020 R. Stange <[email protected]>
// Copyright (C) 2017-2022 R. Stange <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
Expand All @@ -18,11 +18,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include "serialmididevice.h"
#include <circle/sysconfig.h>
#include <assert.h>

CSerialMIDIDevice::CSerialMIDIDevice (CMiniSynthesizer *pSynthesizer, CInterruptSystem *pInterrupt)
: CMIDIDevice (pSynthesizer),
#if RASPPI <= 3 && defined (USE_USB_FIQ)
m_Serial (pInterrupt, FALSE),
#else
m_Serial (pInterrupt, TRUE),
#endif
m_nSerialState (0)
{
}
Expand Down

0 comments on commit 29aa449

Please sign in to comment.