Jump to content

MIDIbox ASIDITY


Sauraen
 Share

Recommended Posts

We finished soldering the front panel circuit board today and did a preliminary assembly of the front panel! Each of the larger buttons has red, yellow, green, and blue ultrabright LEDs under it; the total light power of the front panel will be about that of a 40 watt light bulb. Can't wait for once it's wired up...

 

Edited by Sauraen
Link to comment
Share on other sites

I don't want to spoil your party, but have you tried looking into a light bulb recently? :pinch:

 

Ha ha, I did a test 3x2 matrix on a breadboard with these LEDs, and looking directly down into them is actually uncomfortable. But it's dispersed in all directions by the buttons, so it shouldn't be too bad. :)

Link to comment
Share on other sites

  • 1 month later...

We've been planning to do another video for a long time, but nothing that we would show off is entirely working. E.g. four of eight SIDs are working fine, two are working almost fine, and two not at all (but it's not the SIDs themselves, it's my custom boards for them). I got the OPL3 module working, but again, it's only mostly working--some of the parameters seem to be backwards, and I don't have an already-existing control surface with enough knobs to control all of them. In both cases, what it can do is just play those sound chips in a very vanilla way; without the front panel all done, it's useless to try to run them off the version of the OS that includes the giant modulation matrix and all, because there's no way to control it.

 

But thank you! Hopefully I'll get the rest of the kinks with the front panel straightened out in the next couple weeks, and then make a video just showing that.

Link to comment
Share on other sites

  • 4 weeks later...
  • 4 weeks later...
OPL3 controlled from MIOS32? I'd love to see that code :smile:  :question:  :sleep:  :santa:  :nuke:  :queen:

If you say so! It's not done, so I'll just tease you with the header:

 

// $Id: opl3.h $
/*
 * Header file for MBHP_OPL3 module driver
 *
 * TODO: Make the pins specified to only work for LPC17!
 *
 * ==========================================================================
 *
 *  Copyright © 2012 Sauraen (sauraen@gmail.com)
 *  Licensed for personal non-commercial use only.
 *  All other rights reserved.
 *  
 *  Partially based on SID module driver from:
 *
 *  Copyright © 2008 Thorsten Klose (tk@midibox.org)
 *  Licensed for personal non-commercial use only.
 *  All other rights reserved.
 * 
 * ==========================================================================
 */

#ifndef _OPL3_H
#define _OPL3_H

#ifdef __cplusplus
extern "C" {
#endif

/*
OPL3 Programming Information
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To simplify programming an interface for this driver, the operator-channel
mapping used externally here has been made much more obvious than the way
they are connected inside the actual OPL3. This driver does the conversion.

OPL3 has 36 operators, and up to 20 channels (in 2-op percussion mode). Six
pairs of channels may be merged together individually, to make up to 6 four-
voice channels. The operator and channel numbers are rearranged in this driver
so that the connected ones are always next to each other.

==================================+==================================+
       Operators you use          |     Actual operators in OPL3     |
Chan | 2-Op Mode |   4-Op Mode    |Chan | 2-Op Mode |   4-Op Mode    |
=====+===========+================+=====+===========+================+
  0  |  0,  1    |  0,  1,  2,  3 |  0  |  0,  3    |  0,  3,  6,  9 |
  1  |  2,  3    |        --      |  3  |  6,  9    |        --      |
  2  |  4,  5    |  4,  5,  6,  7 |  1  |  1,  4    |  1,  4,  7, 10 |
  3  |  6,  7    |        --      |  4  |  7, 10    |        --      |
  4  |  8,  9    |  8,  9, 10, 11 |  2  |  2,  5    |  2,  5,  8, 11 |
  5  | 10, 11    |        --      |  5  |  8, 11    |        --      |
  6  | 12, 13    | 12, 13, 14, 15 |  9  | 18, 21    | 18, 21, 24, 27 |
  7  | 14, 15    |        --      | 12  | 24, 27    |        --      |
  8  | 16, 17    | 16, 17, 18, 19 | 10  | 19, 22    | 19, 22, 25, 28 |
  9  | 18, 19    |        --      | 13  | 25, 28    |        --      |
 10  | 20, 21    | 20, 21, 22, 23 | 11  | 20, 23    | 20, 23, 26, 29 |
 11  | 22, 23    |        --      | 14  | 26, 29    |        --      |
-----+-----------+----------------+-----+-----------+----------------+
 12  | 24, 25    |        --      | 15  | 30, 33    |        --      |
 13  | 26, 27    |        --      | 16  | 31, 34    |        --      |
 14  | 28, 29    |        --      | 17  | 32, 35    |        --      |
-----+-----------+----------------+-----+-----------+----------------+
 15  | 30, 31    | 30+31: BD      |  6  | 12, 15    | 12+15: BD      |
 16  | 32, 33    | 32: HH  33: SD |  7  | 13, 16    | 13: HH  16: SD |
 17  | 34, 35    | 34: TT  35: CY |  8  | 14, 17    | 14: TT  17: CY |
=====+===========+================+=====+===========+================+

*/


/////////////////////////////////////////////////////////////////////////////
// Global definitions
/////////////////////////////////////////////////////////////////////////////

// pin mapping for GPIO pins
#ifndef OPL3_SCLK_PORT
#define OPL3_SCLK_PORT         2
#endif
#ifndef OPL3_SCLK_PIN
#define OPL3_SCLK_PIN          3  // J10:D1; shared with SID module SCLK
#endif

#ifndef OPL3_DAT_PORT
#define OPL3_DAT_PORT          2
#endif
#ifndef OPL3_DAT_PIN
#define OPL3_DAT_PIN           8  // J10:D6; shared with SID module DAT6
#endif

#ifndef OPL3_SRLAT_PORT
#define OPL3_SRLAT_PORT        0
#endif
#ifndef OPL3_SRLAT_PIN
#define OPL3_SRLAT_PIN         17 // J19:S1
#endif

#ifndef OPL3_A0_PORT
#define OPL3_A0_PORT           0
#endif
#ifndef OPL3_A0_PIN
#define OPL3_A0_PIN            15 // J19:SC
#endif

#ifndef OPL3_A1_PORT
#define OPL3_A1_PORT           0
#endif
#ifndef OPL3_A1_PIN
#define OPL3_A1_PIN            16 // J19:RC1
#endif

#ifndef OPL3_WR_PORT
#define OPL3_WR_PORT           0
#endif
#ifndef OPL3_WR_PIN
#define OPL3_WR_PIN            18 // J19:S0; connected to OPL3 WR# and CS#
#endif

#ifndef OPL3_RS_PORT
#define OPL3_RS_PORT           0
#endif
#ifndef OPL3_RS_PIN
#define OPL3_RS_PIN            21 // J19:RC2
#endif


/////////////////////////////////////////////////////////////////////////////
// Global Types
/////////////////////////////////////////////////////////////////////////////

typedef union {
  u8 ALL[5];
  struct {
    //Byte 0: 0x20 + operator offset
    u8 fmult:4;     //Multiplier for channel frequency
    u8 ksr:1;       //How much to scale amp EG with pitch
    u8 dosustain:1; //Whether to sustain the note while gate is held
    u8 vibrato:1;   //Whether to use the frequency LFO
    u8 tremelo:1;   //Whether to use the amplitude LFO
    
    //Byte 1: 0x40 + operator offset
    u8 volume:6;    //Volume level of operator, or how much to have it affect the carrier (if it's a modulator)
    u8 ksl:2;       //How much to scale volume with pitch
    
    //Byte 2: 0x60 + operator offset
    u8 decay:4;     //Decay rate for amp EG
    u8 attack:4;    //Attack rate for amp EG
    
    //Byte 3: 0x80 + operator offset
    u8 release:4;   //Release rate for amp EG
    u8 sustain:4;   //Sustain level for amp EG; only held at this value after decay if dosustain == 1, otherwise, immediately goes to release
    
    //Byte 4: 0xF0 + operator offset
    u8 waveform:3;  //Waveform select
    u8 dummy:5;     //Bits ignored by OPL3
  };
} opl3_operator_t;

typedef union {
  u8 ALL[3];
  struct {
    //Byte 0: 0xA0 + channel offset
    u8 fnum_low;    //Lower 8 bits of frequency number
    
    //Byte 1: 0xB0 + operator offset
    u8 fnum_high:2; //Higher 2 bits of frequency number
    u8 block:3;     //Block number
    u8 keyon:1;     //Key on (gate)
    u8 dummy:2;     //Bits ignored by OPL3
    
    //Byte 2: 0xC0 + operator offset
    u8 synthtype:1; //Algorithm selection
    u8 feedback:3;  //Feedback; only works in some operators (one per channel)
    u8 left:1;      //Whether to send this signal to output 1 (A) (left)
    u8 right:1;     //Whether to send this signal to output 2 (B) (right)
    u8 out3:1;      //Whether to send this signal to output 3 ©
    u8 out4:1;      //Whether to send this signal to output 4 (D)
  };
} opl3_channel_t;

typedef union {
  u8 ALL[4];
  struct {
    //Byte 0: 0x05 only in higher register set
    u8 opl3mode:1;  //Whether to act like an OPL3 as opposed to OPL2
    u8 dummy:7;     //Bits ignored by OPL3
    
    //Byte 1: 0x08 only in lower register set
    u8 dummy2:6;    //Bits ignored by OPL3
    u8 notesel:1;   //Which bits of the frequency register to use to determine where to break up the keyboard for key scaling
    u8 csw:1;       //Composite sine wave mode; may not be supported by OPL3 (only OPL2), and nobody on the Internet knows how to use it even there
    
    //Byte 2: 0xBD only in lower register set
    u8 hh:1;        //If in percussion mode, play hi-hat  (operator 32 in this driver)
    u8 cy:1;        //If in percussion mode, play cymbal  (operator 35 in this driver)
    u8 tt:1;        //If in percussion mode, play tom-tom (operator 34 in this driver)
    u8 sd:1;        //If in percussion mode, play snare   (operator 33 in this driver)
    u8 bd:1;        //If in percussion mode, play bass drum (operators 30 and 31 in this driver)
    u8 percussion:1; //Percussion mode
    u8 vibratodepth:1; //How deep the vibrato (frequency LFO) should be
    u8 tremelodepth:1; //How deep the tremelo (amplitude LFO) should be
    
    //Byte 3: 0x04 only in higher register set
    u8 fourop; //Lower six bits are whether four-op mode is enabled for six channels which support them
  };
} opl3_chip_t;


/////////////////////////////////////////////////////////////////////////////
// Export global variables
/////////////////////////////////////////////////////////////////////////////

extern opl3_operator_t opl3_operators[36];
extern opl3_channel_t opl3_channels[18];
extern opl3_chip_t opl3_chip;


/////////////////////////////////////////////////////////////////////////////
// Prototypes
/////////////////////////////////////////////////////////////////////////////

// Call this when setting up the microcontroller. Sets up GPIO pins, internals,
// calls OPL3_Reset().
extern s32 OPL3_Init(void);

// Sends reset signal to OPL3 and then refreshes it with current data.
// Why a synth would have to use this except in initialization I don't know.
// (It's automatically called by OPL3_Init().)
extern s32 OPL3_Reset(void);

// Refreshes all OPL3 registers. Call this after your app is done initializing.
extern s32 OPL3_RefreshAll(void);

// Call this after every control refresh. Refreshes any OPL3 registers that have
// changed since last time.
extern s32 OPL3_OnFrame(void);

// Convenience functions for interacting with OPL3
// You MUST use these functions to write data to OPL3 or the OPL3 will not be
// refreshed with the data on the next frame!

//For an operator
extern s32 OPL3_SetFMult(u8 op, u8 value);
extern s32 OPL3_SetWaveform(u8 op, u8 value);
extern s32 OPL3_SetVibrato(u8 op, u8 value);

extern s32 OPL3_SetVolume(u8 op, u8 value);
extern s32 OPL3_SetTremelo(u8 op, u8 value);
extern s32 OPL3_SetKSL(u8 op, u8 value);

extern s32 OPL3_SetAttack(u8 op, u8 value);
extern s32 OPL3_SetDecay(u8 op, u8 value);
extern s32 OPL3_DoSustain(u8 op, u8 value);
extern s32 OPL3_SetSustain(u8 op, u8 value);
extern s32 OPL3_SetRelease(u8 op, u8 value);
extern s32 OPL3_SetKSR(u8 op, u8 value);

//For a channel
extern s32 OPL3_Gate(u8 chan, u8 value);
extern s32 OPL3_SetFrequency(u8 chan, u16 fnum, u8 block);
extern s32 OPL3_SetFeedback(u8 chan, u8 value);
extern s32 OPL3_SetAlgorithm(u8 chan, u8 value);

extern s32 OPL3_OutLeft(u8 chan, u8 value);
extern s32 OPL3_OutRight(u8 chan, u8 value);
extern s32 OPL3_Out3(u8 chan, u8 value);
extern s32 OPL3_Out4(u8 chan, u8 value);

extern s32 OPL3_SetFourOp(u8 chan, u8 value);

//For the whole OPL3
extern s32 OPL3_SetOpl3Mode(u8 value);
extern s32 OPL3_SetNoteSel(u8 value);
extern s32 OPL3_SetCSW(u8 value);

extern s32 OPL3_SetVibratoDepth(u8 value);
extern s32 OPL3_SetTremeloDepth(u8 value);

extern s32 OPL3_SetPercussionMode(u8 value);
extern s32 OPL3_TriggerBD(u8 value);
extern s32 OPL3_TriggerSD(u8 value);
extern s32 OPL3_TriggerTT(u8 value);
extern s32 OPL3_TriggerHH(u8 value);
extern s32 OPL3_TriggerCY(u8 value);

//Convenience functions for reading
extern u8 OPL3_IsChannel4Op(u8 chan);
extern u8 OPL3_IsOperatorCarrier(u8 op);

#ifdef __cplusplus
}
#endif

#endif /* _SIDFEEDBACK_H */
  • Like 1
Link to comment
Share on other sites

Sweet! I have the components needed for PIC-core and OPL3 module, just need the PCBs, but I'd really rather use a MIOS32 core where I know how to work with the sauce.

 

Any ETA on this? How functional is it? I'd be happy to help you test and polish the code.

Link to comment
Share on other sites

First, I should let you know that I'm not near my equipment for the next three weeks, so I can't try anything and I don't think I have the most updated version of my code. Once I get back, it shouldn't theoretically take long for me to get the OPL3 module entirely working, but knowing my previous inaccuracies in terms of estimating time, I can't give a number. Bug me here if you have questions and I'll spend more time on it. My whole synth won't be done for another year at least, but you won't be using the sequencer or front panel or SIDs so those don't matter.

 

My code is functional enough to get 18-voice polyphony out of the OPL3, but not enough to properly control all the parameters. The key issue seems to be that some but not all of the parameters seem to be either bitflipped or reversed from how they would seem they should be. For instance, when my code calculates the frequency and sends that, it sounds correct (and either of the above conditions would be audibly wrong). However, the ADSR parameters seem to count in reverse (i.e. sending 0xF gives you a value of 0 and 0x0 of 15), and some of the bit flags seem to be flipped as well. Part of the difficulty was that I didn't have any device, besides the front panel of ASIDITY itself, which had enough knobs to control all the parameters of one voice, and the front panel wasn't near done.

 

As far as hardware, you need an LPC17 core and processor with the whole board populated, and you need to make a circuit on veroboard that contains a single 74HC595 output shift register, to convert an SPI signal from the core to the D0-D7 pins of the OPL3. I personally also modified the analog portion of the OPL3 board to fit voltage requirements of my synth, but again that doesn't affect you--you can build it normally if you want.

 

The pins are hooked up this way (ignore the colors, that's my own wires):

J19:
SC  (GPIO0.15): Serial clock for shift register [purple, gray]
RC1 (GPIO0.16): Shift register latch [black]
SI  (GPIO0.17) (no buffer): [green]
SO  (GPIO0.18): Serial data for shift register [blue]
RC2 (GPIO0.21): OPL3 RS (IC#, i.e. Reset) [white]

J28:
SCLK(GPIO2.11): OPL3 A0 [purple, gray]
WS  (GPIO2.12): OPL3 A1 [black]
SDA (GPIO2.13): OPL3 CS/WR [blue]
MCLK(GPIO4.29): 

You could put the pins that I have on J28 on J10 or elsewhere if you want; my build had J10 all used already.

 

Edit: Oh, and I assume you realize that anything higher-level than the module driver, i.e. the application, is completely different for me as for you, and you'll have to write that how you want yourself. This will just get you an API to control all the parameters of the OPL3--which you could write a small application connecting them all to CCs and then plug it into a DAW for instance--but not a complete synth like MBFM with LFOs, extra EGs, etc.

Edited by Sauraen
Link to comment
Share on other sites

Bug me here if you have questions and I'll spend more time on it.

 

Is it done yet? :smile:

 

Like said, I don't mind debuggering, and I'm handing in my MA thesis on monday so I have a few weeks/months/lifetimes of free time to look forward to.

 

As far as hardware, you need an LPC17 core and processor with the whole board populated, and you need to make a circuit on veroboard that contains a single 74HC595 output shift register, to convert an SPI signal from the core to the D0-D7 pins of the OPL3. I personally also modified the analog portion of the OPL3 board to fit voltage requirements of my synth, but again that doesn't affect you--you can build it normally if you want. 

 

Gotcher.

 

Edit: Oh, and I assume you realize that anything higher-level than the module driver, i.e. the application, is completely different for me as for you, and you'll have to write that how you want yourself. This will just get you an API to control all the parameters of the OPL3--which you could write a small application connecting them all to CCs and then plug it into a DAW for instance--but not a complete synth like MBFM with LFOs, extra EGs, etc.

 

This is exactly what I had in mind :smile:

Edited by niklasni1
Link to comment
Share on other sites

  • 4 weeks later...
  • 4 weeks later...

That monster is coming together incredibly well! Awesome job! Still can't wait to hear it in its full glory, though!

Curious - what purpose does the limiting circuits serve when driving the SID outputs? Is it just as a simple compressor or are you trying to get in there some grungy distortion (e.g. diode limiting)?

Link to comment
Share on other sites

  • 3 weeks later...
  • 2 months later...

Although I've been recently working a lot on MIDIbox FM V2.0, I demoed ASIDITY for an electrical engineering class and hence did some work on it. I've gotten the three CPUs to cooperate via MBNET, and have front panel control changes going to the SID core as well as track changes from MIDI messages from the SEQ core. And I wrote another test program (well, two programs, one for SEQ and one for SID cores) that give me control of most of the OPL3 parameters via the front panel. So ASIDITY makes a quick appearance at the end of this video:

 

Edited by Sauraen
Link to comment
Share on other sites

  • 2 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...