Skip to content

Commit

Permalink
Merge pull request #86 from jpcima/pmdwin
Browse files Browse the repository at this point in the history
add PMDWin emulator
  • Loading branch information
Wohlstand authored Mar 3, 2019
2 parents 5aa5df1 + 50d8849 commit 8cd4845
Show file tree
Hide file tree
Showing 13 changed files with 7,422 additions and 2 deletions.
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ option(USE_NUKED_EMULATOR "Use Nuked OPN2 emulator (most accurate, heavy)" ON)
option(USE_GX_EMULATOR "Use Genesis Plus GX emulator (experimental)" OFF)
option(USE_NP2_EMULATOR "Use Neko Project II emulator" ON)
option(USE_MAME_2608_EMULATOR "Use MAME YM2608 emulator" ON)
option(USE_PMDWIN_EMULATOR "Use PMDWin emulator (experimental)" OFF)
# WIP FEATURES
# option(WITH_CPP_EXTRAS "Build with support for C++ extras (features are can be found in 'adlmidi.hpp' header)" OFF)

Expand Down Expand Up @@ -220,6 +221,17 @@ else()
add_definitions(-DOPNMIDI_DISABLE_MAME_2608_EMULATOR)
endif()

if(USE_PMDWIN_EMULATOR)
list(APPEND libOPNMIDI_SOURCES
${libOPNMIDI_SOURCE_DIR}/src/chips/pmdwin_opna.cpp
${libOPNMIDI_SOURCE_DIR}/src/chips/pmdwin/opna.c
${libOPNMIDI_SOURCE_DIR}/src/chips/pmdwin/psg.c
${libOPNMIDI_SOURCE_DIR}/src/chips/pmdwin/rhythmdata.c)
set(HAS_EMULATOR TRUE)
else()
add_definitions(-DOPNMIDI_DISABLE_PMDWIN_EMULATOR)
endif()

if(NOT HAS_EMULATOR)
message(FATAL_ERROR "No emulators enabled! You must enable at least one emulator!")
endif()
Expand Down Expand Up @@ -415,6 +427,7 @@ message("USE_NUKED_EMULATOR = ${USE_NUKED_EMULATOR}")
message("USE_GX_EMULATOR = ${USE_GX_EMULATOR}")
message("USE_NP2_EMULATOR = ${USE_NP2_EMULATOR}")
message("USE_MAME_2608_EMULATOR = ${USE_MAME_2608_EMULATOR}")
message("USE_PMDWIN_EMULATOR = ${USE_PMDWIN_EMULATOR}")

message("===== Utils and extras =====")
message("WITH_MIDIPLAY = ${WITH_MIDIPLAY}")
Expand Down
2 changes: 2 additions & 0 deletions include/opnmidi.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ enum Opn2_Emulator
OPNMIDI_EMU_NP2,
/*! Mame YM2608 */
OPNMIDI_EMU_MAME_2608,
/*! PMDWin OPNA */
OPNMIDI_EMU_PMDWIN,
/*! Count instrument on the level */
OPNMIDI_EMU_end
};
Expand Down
144 changes: 144 additions & 0 deletions src/chips/pmdwin/op.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#ifndef FM_OP_H
#define FM_OP_H

#include <stdint.h>
#define false 0
#define true 1
#define Max(a,b) ((a>b)?a:b)
#define Min(a,b) ((a<b)?a:b)

/* Types ---------------------------------------------------------------- */
typedef int32_t Sample;
typedef int32_t ISample;

/* ---------------------------------------------------------------------------
// Various implementation-specific constants.
// Most are used to either define the bit-width of counters, or the size
// of various constant tables.
*/
#define FM_LFOBITS 8
#define FM_LFOENTS (1 << FM_LFOBITS)
#define FM_OPSINBITS 10
#define FM_OPSINENTS (1 << FM_OPSINBITS)
#define FM_EGBITS 16
#define FM_EGCBITS 18
#define FM_LFOCBITS 14
#define FM_PGBITS 9
#define FM_RATIOBITS 12

typedef enum _EGPhase { next, attack, decay, sustain, release, off } EGPhase;

static inline int Limit(int v, int max, int min)
{
return v > max ? max : (v < min ? min : v);
}

static inline int16_t Limit16(int a)
{
if ((a+0x8000) & ~0xFFFF) return (a>>31) ^ 0x7FFF;
else return a;
}

/* ------------------------------------------------------------------------- */
struct _OPNA;
struct Channel4;

/* Operator ---------------------------------------------------------------- */
typedef struct _FMOperator
{
struct Channel4 *master;

int32_t out, out2;

/* Phase Generator ----------------------------------------------------- */
uint32_t dp; /* Octave (used to define note in conjunction with bn, below). */
uint8_t detune; /* Detune */
uint8_t multiple; /* Multiple */
uint32_t pgcount; /* Phase generator sweep value. Only the top 9 bits are relevant/used. */
uint32_t pgdcount; /* Phase generator increment-per-clock value. Hopefully self-explanatory. */
uint32_t pgdcountl; /* Phase generator detune increment value. Used in the implementation of vibrato. */
/* Equal to pgdcount >> 11. */

/* Envelope Generator -------------------------------------------------- */
uint32_t bn; /* Block/Note */
uint32_t egout;
int eglevel; /* EG ¤Î½ÐÎÏÃÍ */
int eglvnext; /* ¼¡¤Î phase ¤Ë°Ü¤ëÃÍ */
int32_t egstep; /* EG ¤Î¼¡¤ÎÊѰܤޤǤλþ´Ö */
int32_t egstepd; /* egstep ¤Î»þ´Öº¹Ê¬ */
uint8_t egtransa; /* EG ÊѲ½¤Î³ä¹ç (for attack) */
uint8_t egtransd; /* EG ÊѲ½¤Î³ä¹ç (for decay) */

uint32_t ksr; /* key scale rate */
EGPhase phase;
uint8_t ams;
uint8_t ms;

uint8_t keyon; /* current key state */

uint8_t tl; /* Total Level (0-127) */
uint8_t tll; /* Total Level Latch (for CSM mode) */
uint8_t ar; /* Attack Rate (0-63) */
uint8_t dr; /* Decay Rate (0-63) */
uint8_t sr; /* Sustain Rate (0-63) */
uint8_t sl; /* Sustain Level (0-127) */
uint8_t rr; /* Release Rate (0-63) */
uint8_t ks; /* Keyscale (0-3) */
uint8_t ssgtype; /* SSG-Type Envelope Control */

uint8_t amon; /* enable Amplitude Modulation */
uint8_t paramchanged; /* Set whenever f-number or any ADSR constants */
/* are set in OPNASetReg(), as well as upon */
/* chip reset and chip "DAC" samplerate change. */
/* Causes the envelope generator to reset its */
/* internal state, also sets correct increments */
/* for the phase generator. */
uint8_t mute;
} FMOperator;

/* 4-op Channel ------------------------------------------------------------ */
typedef struct Channel4
{
struct _OPNA *master;
uint32_t fb;
int buf[4];
uint8_t idx[6];
int *pms;
uint16_t panl;
uint16_t panr;
FMOperator op[4];
} Channel4;

/* OPNA Rhythm Generator --------------------------------------------------- */
typedef struct Rhythm {
uint8_t pan;
int8_t level;
int8_t volume;
int8_t* sample; /* Rhythm sample data */
uint32_t size; /* Rhythm sample data size */
uint32_t pos; /* Current index into rhytm sample data array */
uint32_t step; /* Amount to increment the above by every time */
/* RhythmMix() gets called. */
uint32_t rate; /* Samplerate of rhythm sample data */
/* (44100Hz in this implementation). */
} Rhythm;

#ifdef __cplusplus
extern "C" {
#endif

/* --------------------------------------------------------------------------
// Miscellaneous and probably irrelevant function prototypes. */
void OperatorInit(Channel4 *ch4, FMOperator *op);
void OperatorReset(FMOperator *op);
void OperatorPrepare(FMOperator *op);

static inline uint32_t IsOn(FMOperator *op) {
return (op->phase - off);
}

#ifdef __cplusplus
}
#endif

#endif
Loading

0 comments on commit 8cd4845

Please sign in to comment.