- integrate zmusic into normal build process

This commit is contained in:
Rachael Alexanderson 2025-07-30 00:37:50 -04:00
commit 397976738f
No known key found for this signature in database
GPG key ID: 26A8ACCE97115EE0
23 changed files with 8409 additions and 8420 deletions

View file

@ -198,14 +198,14 @@ endmacro()
include( CheckFunctionExists )
macro( require_stricmp )
macro( gz_require_stricmp )
CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS )
if( NOT STRICMP_EXISTS )
add_definitions( -Dstricmp=strcasecmp )
endif()
endmacro()
macro( require_strnicmp )
macro( gz_require_strnicmp )
CHECK_FUNCTION_EXISTS( strnicmp STRNICMP_EXISTS )
if( NOT STRNICMP_EXISTS )
add_definitions( -Dstrnicmp=strncasecmp )
@ -219,6 +219,7 @@ find_package( VPX )
if (NOT FORCE_INTERNAL_CPPDAP)
find_package( cppdap CONFIG )
endif()
find_package( ZMusic )
include( TargetArch )
@ -402,6 +403,18 @@ else()
set( CPPDAP_FOUND TRUE )
endif()
# ZMUSIC
if( ZMUSIC_FOUND AND NOT FORCE_INTERNAL_ZMUSIC )
message( STATUS "Using system zmusic library, includes found at ${ZMUSIC_INCLUDE_DIR}" )
else()
message( STATUS "Using internal zmusic library" )
add_subdirectory( libraries/zmusic )
set( ZMUSIC_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zmusic" )
set( ZMUSIC_INCLUDE_DIR ${ZMUSIC_ROOT_PATH}/include )
set( ZMUSIC_LIBRARIES zmusic )
set( ZMUSIC_FOUND TRUE )
endif()
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/lzma/C" )
if( NOT CMAKE_CROSSCOMPILING )
@ -423,7 +436,7 @@ install(DIRECTORY docs/
option( DYN_OPENAL "Dynamically load OpenAL" ON )
add_subdirectory( libraries/lzma )
add_subdirectory( libraries/miniz )
#add_subdirectory( libraries/miniz ) #ZMusic already includes this
add_subdirectory( tools )
add_subdirectory( wadsrc )
add_subdirectory( wadsrc_bm )

View file

@ -1,19 +1,19 @@
A quote from a letter sent by Willy Reeve to Vitaly Novichkov
as a reply from a letter sent by Reality's (https://www.3eality.com/)
contact form
----------------------------------------------------------------
All source code supplied with RAD is in the public domain.
----------------------------------------------------------------
================================================================
The complete letter:
================================================================
Hi,
All source code supplied with RAD is in the public domain.
We'll clarify that in the documentation for the next release.
Later...
SHAYDE
================================================================
A quote from a letter sent by Willy Reeve to Vitaly Novichkov
as a reply from a letter sent by Reality's (https://www.3eality.com/)
contact form
----------------------------------------------------------------
All source code supplied with RAD is in the public domain.
----------------------------------------------------------------
================================================================
The complete letter:
================================================================
Hi,
All source code supplied with RAD is in the public domain.
We'll clarify that in the documentation for the next release.
Later...
SHAYDE
================================================================

View file

@ -1,19 +1,19 @@
A quote from a letter sent by Willy Reeve to Vitaly Novichkov
as a reply from a letter sent by Reality's (https://www.3eality.com/)
contact form
----------------------------------------------------------------
All source code supplied with RAD is in the public domain.
----------------------------------------------------------------
================================================================
The complete letter:
================================================================
Hi,
All source code supplied with RAD is in the public domain.
We'll clarify that in the documentation for the next release.
Later...
SHAYDE
================================================================
A quote from a letter sent by Willy Reeve to Vitaly Novichkov
as a reply from a letter sent by Reality's (https://www.3eality.com/)
contact form
----------------------------------------------------------------
All source code supplied with RAD is in the public domain.
----------------------------------------------------------------
================================================================
The complete letter:
================================================================
Hi,
All source code supplied with RAD is in the public domain.
We'll clarify that in the documentation for the next release.
Later...
SHAYDE
================================================================

View file

@ -1,347 +1,347 @@
/*
* Copyright (C) 2023 nukeykt
*
* This file is part of YMF262-LLE.
*
* 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 the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* YMF262 emulator
* Thanks:
* John McMaster (siliconpr0n.org):
* YMF262 decap and die shot
*
*/
#pragma once
#ifndef NUKED_FMOPL3_H
#define NUKED_FMOPL3_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef struct
{
int mclk;
int address;
int data_i;
int ic;
int cs;
int rd;
int wr;
} fmopl3_input_t;
typedef struct
{
fmopl3_input_t input;
int mclk1;
int mclk2;
int aclk1;
int aclk2;
int clk1;
int clk2;
int rclk1;
int rclk2;
int o_clk1;
int o_clk2;
int o_rclk1;
int o_rclk2;
int o_wrcheck;
int o_data_latch;
int o_bank_latch;
int o_reset0;
int o_ra_w1_l1;
int prescaler1_reset[2];
int prescaler1_cnt[2];
int prescaler2_reset_l[2];
int prescaler2_cnt[2];
int prescaler2_reset;
int prescaler2_l1[2];
int prescaler2_l2;
int prescaler2_l3[2];
int prescaler2_l4;
int prescaler2_l5[2];
int prescaler2_l6[2];
int prescaler2_l7;
int fsm_cnt1[2];
int fsm_cnt2[2];
int fsm_cnt3[2];
int fsm_cnt;
int fsm_reset_l[2];
int fsm_out[17];
int fsm_l1[2];
int fsm_l2[2];
int fsm_l3[2];
int fsm_l4[2];
int fsm_l5[2];
int fsm_l6[2];
int fsm_l7[2];
int fsm_l8[2];
int fsm_l9[2];
int fsm_l10[2];
int ic_latch[2];
int io_rd;
int io_wr;
int io_cs;
int io_a0;
int io_a1;
int io_read;
int io_write;
int io_write0;
int io_write1;
int io_bank;
int data_latch;
int bank_latch;
int bank_masked;
int reg_sel1;
int reg_sel2;
int reg_sel3;
int reg_sel4;
int reg_sel5;
int reg_sel8;
int reg_selbd;
int reg_test0;
int reg_timer1;
int reg_timer2;
int reg_notesel;
int rhythm;
int reg_rh_kon;
int reg_da;
int reg_dv;
int reg_test1;
int reg_new;
int reg_4op;
int reg_t1_mask;
int reg_t2_mask;
int reg_t1_start;
int reg_t2_start;
int lfo_cnt[2];
int vib_cnt[2];
int t1_step;
int t2_step;
int am_step;
int vib_step;
int rh_sel0;
int rh_sel[2];
int keyon_comb;
int ra_address_latch;
int ra_address_good;
int ra_data_latch;
int ra_cnt1[2];
int ra_cnt2[2];
int ra_cnt3[2];
int ra_cnt4[2];
int ra_cnt;
int ra_rst_l[2];
int ra_w1_l1;
int ra_w1_l2;
int ra_write;
int ra_write_a;
int ra_multi[36];
int ra_ksr[36];
int ra_egt[36];
int ra_am[36];
int ra_vib[36];
int ra_tl[36];
int ra_ksl[36];
int ra_ar[36];
int ra_dr[36];
int ra_sl[36];
int ra_rr[36];
int ra_wf[36];
int ra_fnum[18];
int ra_block[18];
int ra_keyon[18];
int ra_connect[18];
int ra_fb[18];
int ra_pan[18];
int ra_connect_pair[18];
int multi[2];
int ksr[2];
int egt[2];
int am[2];
int vib[2];
int tl[2];
int ksl[2];
int ar[2];
int dr[2];
int sl[2];
int rr[2];
int wf[2];
int fnum[2];
int block[2];
int keyon[2];
int connect[2];
int fb[2];
int pan[2];
int connect_pair[2];
int64_t ra_dbg1[2];
int ra_dbg2[2];
int ra_dbg_load[2];
int fb_l[2][2];
int pan_l[2][2];
int write0_sr;
int write0_l[4];
int write0;
int write1_sr;
int write1_l[4];
int write1;
int connect_l[2];
int connect_pair_l[2];
int t1_cnt[2];
int t2_cnt[2];
int t1_of[2];
int t2_of[2];
int t1_status;
int t2_status;
int timer_st_load_l;
int timer_st_load;
int t1_start;
int t2_start;
int t1_start_l[2];
int t2_start_l[2];
int reset0;
int reset1;
int pg_phase_o[4];
int pg_dbg[2];
int pg_dbg_load_l[2];
int noise_lfsr[2];
int pg_index[2];
int pg_cells[36];
int pg_out_rhy;
int trem_load_l;
int trem_load;
int trem_st_load_l;
int trem_st_load;
int trem_carry[2];
int trem_value[2];
int trem_dir[2];
int trem_step;
int trem_out;
int trem_of[2];
int eg_load_l1[2];
int eg_load_l;
int eg_load;
int64_t eg_timer_masked[2];
int eg_carry[2];
int eg_mask[2];
int eg_subcnt[2];
int eg_subcnt_l[2];
int eg_sync_l[2];
int eg_timer_low;
int eg_shift;
int eg_timer_dbg[2];
int eg_timer_i;
int eg_timer_o[4];
int eg_state_o[4];
int eg_level_o[4];
int eg_index[2];
int eg_cells[36];
int eg_out[2];
int eg_dbg[2];
int eg_dbg_load_l[2];
int hh_load;
int tc_load;
int hh_bit2;
int hh_bit3;
int hh_bit7;
int hh_bit8;
int tc_bit3;
int tc_bit5;
int op_logsin[2];
int op_saw[2];
int op_saw_phase[2];
int op_shift[2];
int op_pow[2];
int op_mute[2];
int op_sign[2];
int op_fb[4][13][2];
int op_mod[2];
int op_value;
int accm_a[2];
int accm_b[2];
int accm_c[2];
int accm_d[2];
int accm_shift_a[2];
int accm_shift_b[2];
int accm_shift_c[2];
int accm_shift_d[2];
int accm_load_ac_l;
int accm_load_ac;
int accm_load_bd_l;
int accm_load_bd;
int accm_a_of;
int accm_a_sign;
int accm_b_of;
int accm_b_sign;
int accm_c_of;
int accm_c_sign;
int accm_d_of;
int accm_d_sign;
int o_doab;
int o_docd;
int o_sy;
int o_smpac;
int o_smpbd;
int o_irq_pull;
int o_test;
int data_o;
int data_z;
} fmopl3_t;
extern void FMOPL3_Clock(fmopl3_t *chip);
#ifdef __cplusplus
}
#endif
#endif /* NUKED_FMOPL3_H */
/*
* Copyright (C) 2023 nukeykt
*
* This file is part of YMF262-LLE.
*
* 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 the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* YMF262 emulator
* Thanks:
* John McMaster (siliconpr0n.org):
* YMF262 decap and die shot
*
*/
#pragma once
#ifndef NUKED_FMOPL3_H
#define NUKED_FMOPL3_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef struct
{
int mclk;
int address;
int data_i;
int ic;
int cs;
int rd;
int wr;
} fmopl3_input_t;
typedef struct
{
fmopl3_input_t input;
int mclk1;
int mclk2;
int aclk1;
int aclk2;
int clk1;
int clk2;
int rclk1;
int rclk2;
int o_clk1;
int o_clk2;
int o_rclk1;
int o_rclk2;
int o_wrcheck;
int o_data_latch;
int o_bank_latch;
int o_reset0;
int o_ra_w1_l1;
int prescaler1_reset[2];
int prescaler1_cnt[2];
int prescaler2_reset_l[2];
int prescaler2_cnt[2];
int prescaler2_reset;
int prescaler2_l1[2];
int prescaler2_l2;
int prescaler2_l3[2];
int prescaler2_l4;
int prescaler2_l5[2];
int prescaler2_l6[2];
int prescaler2_l7;
int fsm_cnt1[2];
int fsm_cnt2[2];
int fsm_cnt3[2];
int fsm_cnt;
int fsm_reset_l[2];
int fsm_out[17];
int fsm_l1[2];
int fsm_l2[2];
int fsm_l3[2];
int fsm_l4[2];
int fsm_l5[2];
int fsm_l6[2];
int fsm_l7[2];
int fsm_l8[2];
int fsm_l9[2];
int fsm_l10[2];
int ic_latch[2];
int io_rd;
int io_wr;
int io_cs;
int io_a0;
int io_a1;
int io_read;
int io_write;
int io_write0;
int io_write1;
int io_bank;
int data_latch;
int bank_latch;
int bank_masked;
int reg_sel1;
int reg_sel2;
int reg_sel3;
int reg_sel4;
int reg_sel5;
int reg_sel8;
int reg_selbd;
int reg_test0;
int reg_timer1;
int reg_timer2;
int reg_notesel;
int rhythm;
int reg_rh_kon;
int reg_da;
int reg_dv;
int reg_test1;
int reg_new;
int reg_4op;
int reg_t1_mask;
int reg_t2_mask;
int reg_t1_start;
int reg_t2_start;
int lfo_cnt[2];
int vib_cnt[2];
int t1_step;
int t2_step;
int am_step;
int vib_step;
int rh_sel0;
int rh_sel[2];
int keyon_comb;
int ra_address_latch;
int ra_address_good;
int ra_data_latch;
int ra_cnt1[2];
int ra_cnt2[2];
int ra_cnt3[2];
int ra_cnt4[2];
int ra_cnt;
int ra_rst_l[2];
int ra_w1_l1;
int ra_w1_l2;
int ra_write;
int ra_write_a;
int ra_multi[36];
int ra_ksr[36];
int ra_egt[36];
int ra_am[36];
int ra_vib[36];
int ra_tl[36];
int ra_ksl[36];
int ra_ar[36];
int ra_dr[36];
int ra_sl[36];
int ra_rr[36];
int ra_wf[36];
int ra_fnum[18];
int ra_block[18];
int ra_keyon[18];
int ra_connect[18];
int ra_fb[18];
int ra_pan[18];
int ra_connect_pair[18];
int multi[2];
int ksr[2];
int egt[2];
int am[2];
int vib[2];
int tl[2];
int ksl[2];
int ar[2];
int dr[2];
int sl[2];
int rr[2];
int wf[2];
int fnum[2];
int block[2];
int keyon[2];
int connect[2];
int fb[2];
int pan[2];
int connect_pair[2];
int64_t ra_dbg1[2];
int ra_dbg2[2];
int ra_dbg_load[2];
int fb_l[2][2];
int pan_l[2][2];
int write0_sr;
int write0_l[4];
int write0;
int write1_sr;
int write1_l[4];
int write1;
int connect_l[2];
int connect_pair_l[2];
int t1_cnt[2];
int t2_cnt[2];
int t1_of[2];
int t2_of[2];
int t1_status;
int t2_status;
int timer_st_load_l;
int timer_st_load;
int t1_start;
int t2_start;
int t1_start_l[2];
int t2_start_l[2];
int reset0;
int reset1;
int pg_phase_o[4];
int pg_dbg[2];
int pg_dbg_load_l[2];
int noise_lfsr[2];
int pg_index[2];
int pg_cells[36];
int pg_out_rhy;
int trem_load_l;
int trem_load;
int trem_st_load_l;
int trem_st_load;
int trem_carry[2];
int trem_value[2];
int trem_dir[2];
int trem_step;
int trem_out;
int trem_of[2];
int eg_load_l1[2];
int eg_load_l;
int eg_load;
int64_t eg_timer_masked[2];
int eg_carry[2];
int eg_mask[2];
int eg_subcnt[2];
int eg_subcnt_l[2];
int eg_sync_l[2];
int eg_timer_low;
int eg_shift;
int eg_timer_dbg[2];
int eg_timer_i;
int eg_timer_o[4];
int eg_state_o[4];
int eg_level_o[4];
int eg_index[2];
int eg_cells[36];
int eg_out[2];
int eg_dbg[2];
int eg_dbg_load_l[2];
int hh_load;
int tc_load;
int hh_bit2;
int hh_bit3;
int hh_bit7;
int hh_bit8;
int tc_bit3;
int tc_bit5;
int op_logsin[2];
int op_saw[2];
int op_saw_phase[2];
int op_shift[2];
int op_pow[2];
int op_mute[2];
int op_sign[2];
int op_fb[4][13][2];
int op_mod[2];
int op_value;
int accm_a[2];
int accm_b[2];
int accm_c[2];
int accm_d[2];
int accm_shift_a[2];
int accm_shift_b[2];
int accm_shift_c[2];
int accm_shift_d[2];
int accm_load_ac_l;
int accm_load_ac;
int accm_load_bd_l;
int accm_load_bd;
int accm_a_of;
int accm_a_sign;
int accm_b_of;
int accm_b_sign;
int accm_c_of;
int accm_c_sign;
int accm_d_of;
int accm_d_sign;
int o_doab;
int o_docd;
int o_sy;
int o_smpac;
int o_smpbd;
int o_irq_pull;
int o_test;
int data_o;
int data_z;
} fmopl3_t;
extern void FMOPL3_Clock(fmopl3_t *chip);
#ifdef __cplusplus
}
#endif
#endif /* NUKED_FMOPL3_H */

File diff suppressed because it is too large Load diff

View file

@ -1,53 +1,53 @@
/*
**
** software implementation of Yamaha FM sound generator (YM2612/YM3438)
**
** Original code (MAME fm.c)
**
** Copyright (C) 2001, 2002, 2003 Jarek Burczynski (bujar at mame dot net)
** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development
**
** Version 1.4 (final beta)
**
** Additional code & fixes by Eke-Eke for Genesis Plus GX
** Adaptations by Jean Pierre Cimalando for use in libOPNMIDI.
** (based on fee2bc8 dated Jan 7th, 2018)
**
*/
#ifndef _H_YM2612_
#define _H_YM2612_
#if defined(__cplusplus)
extern "C" {
#endif
enum {
YM2612_DISCRETE = 0,
YM2612_INTEGRATED,
YM2612_ENHANCED
};
struct YM2612GX;
typedef struct YM2612GX YM2612GX;
/* typedef signed int FMSAMPLE; */
typedef signed short FMSAMPLE;
extern YM2612GX *YM2612GXAlloc();
extern void YM2612GXFree(YM2612GX *ym2612);
extern void YM2612GXInit(YM2612GX *ym2612);
extern void YM2612GXConfig(YM2612GX *ym2612, int type);
extern void YM2612GXResetChip(YM2612GX *ym2612);
extern void YM2612GXPreGenerate(YM2612GX *ym2612);
extern void YM2612GXPostGenerate(YM2612GX *ym2612, unsigned int count);
extern void YM2612GXGenerateOneNative(YM2612GX *ym2612, FMSAMPLE *frame);
extern void YM2612GXWrite(YM2612GX *ym2612, unsigned int a, unsigned int v);
extern void YM2612GXWritePan(YM2612GX *chip, int c, unsigned char v);
extern unsigned int YM2612GXRead(YM2612GX *ym2612);
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif /* _YM2612_ */
/*
**
** software implementation of Yamaha FM sound generator (YM2612/YM3438)
**
** Original code (MAME fm.c)
**
** Copyright (C) 2001, 2002, 2003 Jarek Burczynski (bujar at mame dot net)
** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development
**
** Version 1.4 (final beta)
**
** Additional code & fixes by Eke-Eke for Genesis Plus GX
** Adaptations by Jean Pierre Cimalando for use in libOPNMIDI.
** (based on fee2bc8 dated Jan 7th, 2018)
**
*/
#ifndef _H_YM2612_
#define _H_YM2612_
#if defined(__cplusplus)
extern "C" {
#endif
enum {
YM2612_DISCRETE = 0,
YM2612_INTEGRATED,
YM2612_ENHANCED
};
struct YM2612GX;
typedef struct YM2612GX YM2612GX;
/* typedef signed int FMSAMPLE; */
typedef signed short FMSAMPLE;
extern YM2612GX *YM2612GXAlloc();
extern void YM2612GXFree(YM2612GX *ym2612);
extern void YM2612GXInit(YM2612GX *ym2612);
extern void YM2612GXConfig(YM2612GX *ym2612, int type);
extern void YM2612GXResetChip(YM2612GX *ym2612);
extern void YM2612GXPreGenerate(YM2612GX *ym2612);
extern void YM2612GXPostGenerate(YM2612GX *ym2612, unsigned int count);
extern void YM2612GXGenerateOneNative(YM2612GX *ym2612, FMSAMPLE *frame);
extern void YM2612GXWrite(YM2612GX *ym2612, unsigned int a, unsigned int v);
extern void YM2612GXWritePan(YM2612GX *chip, int c, unsigned char v);
extern unsigned int YM2612GXRead(YM2612GX *ym2612);
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif /* _YM2612_ */

View file

@ -1,15 +1,15 @@
#ifndef incl_diag_h
#define incl_diag_h
#define LOG0(m) void (0)
#define LOG1(m,a) void (0)
#define LOG2(m,a,b) void (0)
#define LOG3(m,a,b,c) void (0)
#define LOG4(m,a,b,c,d) void (0)
#define LOG5(m,a,b,c,d,e) void (0)
#define LOG6(m,a,b,c,d,e,f) void (0)
#define LOG7(m,a,b,c,d,e,f,g) void (0)
#define LOG8(m,a,b,c,d,e,f,g,h) void (0)
#define LOG9(m,a,b,c,d,e,f,g,h,i) void (0)
#endif // incl_diag_h
#ifndef incl_diag_h
#define incl_diag_h
#define LOG0(m) void (0)
#define LOG1(m,a) void (0)
#define LOG2(m,a,b) void (0)
#define LOG3(m,a,b,c) void (0)
#define LOG4(m,a,b,c,d) void (0)
#define LOG5(m,a,b,c,d,e) void (0)
#define LOG6(m,a,b,c,d,e,f) void (0)
#define LOG7(m,a,b,c,d,e,f,g) void (0)
#define LOG8(m,a,b,c,d,e,f,g,h) void (0)
#define LOG9(m,a,b,c,d,e,f,g,h,i) void (0)
#endif // incl_diag_h

View file

@ -1,177 +1,177 @@
// $Id: file.cpp,v 1.6 1999/12/28 11:14:05 cisc Exp $
#include <stdio.h>
#include "fmgen_types.h"
#include "fmgen_headers.h"
#include "fmgen_file.h"
// ---------------------------------------------------------------------------
// 構築/消滅
// ---------------------------------------------------------------------------
FileIO::FileIO()
{
flags = 0;
}
FileIO::FileIO(const char* filename, uint flg)
{
flags = 0;
Open(filename, flg);
}
FileIO::~FileIO()
{
Close();
}
// ---------------------------------------------------------------------------
// ファイルを開く
// ---------------------------------------------------------------------------
bool FileIO::Open(const char* filename, uint flg)
{
char mode[5] = "rwb";
Close();
strncpy(path, filename, MAX_PATH - 1);
if(flg & readonly)
strcpy(mode, "rb");
else {
if(flg & create)
strcpy(mode, "rwb+");
else
strcpy(mode, "rwb");
}
pfile = fopen(filename, mode);
flags = (flg & readonly) | (pfile == NULL ? 0 : open);
if (pfile == NULL)
error = file_not_found;
SetLogicalOrigin(0);
return !(pfile == NULL);
}
// ---------------------------------------------------------------------------
// ファイルがない場合は作成
// ---------------------------------------------------------------------------
bool FileIO::CreateNew(const char* filename)
{
uint flg = create;
return Open(filename, flg);
}
// ---------------------------------------------------------------------------
// ファイルを作り直す
// ---------------------------------------------------------------------------
bool FileIO::Reopen(uint flg)
{
if (!(flags & open)) return false;
if ((flags & readonly) && (flg & create)) return false;
if (flags & readonly) flg |= readonly;
return Open(path, flg);
}
// ---------------------------------------------------------------------------
// ファイルを閉じる
// ---------------------------------------------------------------------------
void FileIO::Close()
{
if (GetFlags() & open)
{
fclose(pfile);
flags = 0;
}
}
// ---------------------------------------------------------------------------
// ファイル殻の読み出し
// ---------------------------------------------------------------------------
int32 FileIO::Read(void* dest, int32 size)
{
if (!(GetFlags() & open))
return -1;
size_t readsize;
if (!(readsize = fread(dest, 1, static_cast<size_t>(size), pfile)))
return -1;
return size;
}
// ---------------------------------------------------------------------------
// ファイルへの書き出し
// ---------------------------------------------------------------------------
int32 FileIO::Write(const void* dest, int32 size)
{
if (!(GetFlags() & open) || (GetFlags() & readonly))
return -1;
size_t writtensize;
if (!(writtensize = fwrite(dest, 1, static_cast<size_t>(size), pfile)))
return -1;
return static_cast<int32>(writtensize);
}
// ---------------------------------------------------------------------------
// ファイルをシーク
// ---------------------------------------------------------------------------
bool FileIO::Seek(int32 pos, SeekMethod method)
{
if (!(GetFlags() & open))
return false;
int origin;
switch (method)
{
case begin:
origin = SEEK_SET;
break;
case current:
origin = SEEK_CUR;
break;
case end:
origin = SEEK_END;
break;
default:
return false;
}
return (fseek(pfile, pos, origin) != 0);
}
// ---------------------------------------------------------------------------
// ファイルの位置を得る
// ---------------------------------------------------------------------------
int32 FileIO::Tellp()
{
if (!(GetFlags() & open))
return 0;
return static_cast<int32>(ftell(pfile));
}
// ---------------------------------------------------------------------------
// 現在の位置をファイルの終端とする
// ---------------------------------------------------------------------------
bool FileIO::SetEndOfFile()
{
if (!(GetFlags() & open))
return false;
return Seek(0, end);
}
// $Id: file.cpp,v 1.6 1999/12/28 11:14:05 cisc Exp $
#include <stdio.h>
#include "fmgen_types.h"
#include "fmgen_headers.h"
#include "fmgen_file.h"
// ---------------------------------------------------------------------------
// 構築/消滅
// ---------------------------------------------------------------------------
FileIO::FileIO()
{
flags = 0;
}
FileIO::FileIO(const char* filename, uint flg)
{
flags = 0;
Open(filename, flg);
}
FileIO::~FileIO()
{
Close();
}
// ---------------------------------------------------------------------------
// ファイルを開く
// ---------------------------------------------------------------------------
bool FileIO::Open(const char* filename, uint flg)
{
char mode[5] = "rwb";
Close();
strncpy(path, filename, MAX_PATH - 1);
if(flg & readonly)
strcpy(mode, "rb");
else {
if(flg & create)
strcpy(mode, "rwb+");
else
strcpy(mode, "rwb");
}
pfile = fopen(filename, mode);
flags = (flg & readonly) | (pfile == NULL ? 0 : open);
if (pfile == NULL)
error = file_not_found;
SetLogicalOrigin(0);
return !(pfile == NULL);
}
// ---------------------------------------------------------------------------
// ファイルがない場合は作成
// ---------------------------------------------------------------------------
bool FileIO::CreateNew(const char* filename)
{
uint flg = create;
return Open(filename, flg);
}
// ---------------------------------------------------------------------------
// ファイルを作り直す
// ---------------------------------------------------------------------------
bool FileIO::Reopen(uint flg)
{
if (!(flags & open)) return false;
if ((flags & readonly) && (flg & create)) return false;
if (flags & readonly) flg |= readonly;
return Open(path, flg);
}
// ---------------------------------------------------------------------------
// ファイルを閉じる
// ---------------------------------------------------------------------------
void FileIO::Close()
{
if (GetFlags() & open)
{
fclose(pfile);
flags = 0;
}
}
// ---------------------------------------------------------------------------
// ファイル殻の読み出し
// ---------------------------------------------------------------------------
int32 FileIO::Read(void* dest, int32 size)
{
if (!(GetFlags() & open))
return -1;
size_t readsize;
if (!(readsize = fread(dest, 1, static_cast<size_t>(size), pfile)))
return -1;
return size;
}
// ---------------------------------------------------------------------------
// ファイルへの書き出し
// ---------------------------------------------------------------------------
int32 FileIO::Write(const void* dest, int32 size)
{
if (!(GetFlags() & open) || (GetFlags() & readonly))
return -1;
size_t writtensize;
if (!(writtensize = fwrite(dest, 1, static_cast<size_t>(size), pfile)))
return -1;
return static_cast<int32>(writtensize);
}
// ---------------------------------------------------------------------------
// ファイルをシーク
// ---------------------------------------------------------------------------
bool FileIO::Seek(int32 pos, SeekMethod method)
{
if (!(GetFlags() & open))
return false;
int origin;
switch (method)
{
case begin:
origin = SEEK_SET;
break;
case current:
origin = SEEK_CUR;
break;
case end:
origin = SEEK_END;
break;
default:
return false;
}
return (fseek(pfile, pos, origin) != 0);
}
// ---------------------------------------------------------------------------
// ファイルの位置を得る
// ---------------------------------------------------------------------------
int32 FileIO::Tellp()
{
if (!(GetFlags() & open))
return 0;
return static_cast<int32>(ftell(pfile));
}
// ---------------------------------------------------------------------------
// 現在の位置をファイルの終端とする
// ---------------------------------------------------------------------------
bool FileIO::SetEndOfFile()
{
if (!(GetFlags() & open))
return false;
return Seek(0, end);
}

View file

@ -1,64 +1,64 @@
// $Id: file.h,v 1.6 1999/11/26 10:14:09 cisc Exp $
#if !defined(win32_file_h)
#define win32_file_h
#include "fmgen_types.h"
// ---------------------------------------------------------------------------
class FileIO
{
public:
enum Flags
{
open = 0x000001,
readonly = 0x000002,
create = 0x000004
};
enum SeekMethod
{
begin = 0, current = 1, end = 2
};
enum Error
{
success = 0,
file_not_found,
sharing_violation,
unknown = -1
};
public:
FileIO();
FileIO(const char* filename, uint flg = 0);
virtual ~FileIO();
bool Open(const char* filename, uint flg = 0);
bool CreateNew(const char* filename);
bool Reopen(uint flg = 0);
void Close();
Error GetError() { return error; }
int32 Read(void* dest, int32 len);
int32 Write(const void* src, int32 len);
bool Seek(int32 fpos, SeekMethod method);
int32 Tellp();
bool SetEndOfFile();
uint GetFlags() { return flags; }
void SetLogicalOrigin(int32 origin) { lorigin = origin; }
private:
FILE* pfile;
uint flags;
uint32 lorigin;
Error error;
char path[MAX_PATH];
FileIO(const FileIO&);
const FileIO& operator=(const FileIO&);
};
#endif //
// $Id: file.h,v 1.6 1999/11/26 10:14:09 cisc Exp $
#if !defined(win32_file_h)
#define win32_file_h
#include "fmgen_types.h"
// ---------------------------------------------------------------------------
class FileIO
{
public:
enum Flags
{
open = 0x000001,
readonly = 0x000002,
create = 0x000004
};
enum SeekMethod
{
begin = 0, current = 1, end = 2
};
enum Error
{
success = 0,
file_not_found,
sharing_violation,
unknown = -1
};
public:
FileIO();
FileIO(const char* filename, uint flg = 0);
virtual ~FileIO();
bool Open(const char* filename, uint flg = 0);
bool CreateNew(const char* filename);
bool Reopen(uint flg = 0);
void Close();
Error GetError() { return error; }
int32 Read(void* dest, int32 len);
int32 Write(const void* src, int32 len);
bool Seek(int32 fpos, SeekMethod method);
int32 Tellp();
bool SetEndOfFile();
uint GetFlags() { return flags; }
void SetLogicalOrigin(int32 origin) { lorigin = origin; }
private:
FILE* pfile;
uint flags;
uint32 lorigin;
Error error;
char path[MAX_PATH];
FileIO(const FileIO&);
const FileIO& operator=(const FileIO&);
};
#endif //

File diff suppressed because it is too large Load diff

View file

@ -1,342 +1,342 @@
// ---------------------------------------------------------------------------
// FM Sound Generator
// Copyright (C) cisc 1998, 2001.
// ---------------------------------------------------------------------------
// $Id: fmgen.h,v 1.37 2003/08/25 13:33:11 cisc Exp $
#ifndef FM_GEN_H
#define FM_GEN_H
#include "fmgen_types.h"
// ---------------------------------------------------------------------------
// 出力サンプルの型
//
// libOPNMIDI: change int32 to int16
#define FM_SAMPLETYPE int16 // int16 or int32
// ---------------------------------------------------------------------------
// 定数その1
// 静的テーブルのサイズ
#define FM_LFOBITS 8 // 変更不可
#define FM_TLBITS 7
// ---------------------------------------------------------------------------
#define FM_TLENTS (1 << FM_TLBITS)
#define FM_LFOENTS (1 << FM_LFOBITS)
#define FM_TLPOS (FM_TLENTS/4)
// サイン波の精度は 2^(1/256)
#define FM_CLENTS (0x1000 * 2) // sin + TL + LFO
// ---------------------------------------------------------------------------
namespace FM
{
// Types ----------------------------------------------------------------
typedef FM_SAMPLETYPE Sample;
typedef int32 ISample;
enum OpType { typeN=0, typeM=1 };
enum EGPhase { next, attack, decay, sustain, release, off };
void StoreSample(ISample& dest, int data);
class Chip;
struct ChipData;
// Operator -------------------------------------------------------------
struct OperatorData {
ISample out_;
ISample out2_;
ISample in2_;
uint dp_;
uint detune_;
uint detune2_;
uint multiple_;
uint32 pg_count_;
uint32 pg_diff_;
int32 pg_diff_lfo_;
OpType type_;
uint bn_;
int eg_level_;
int eg_level_on_next_phase_;
int eg_count_;
int eg_count_diff_;
int eg_out_;
int tl_out_;
int eg_rate_;
int eg_curve_count_;
#if 0 // libOPNMIDI: experimental SSG-EG
int ssg_offset_;
int ssg_vector_;
int ssg_phase_;
#endif
uint key_scale_rate_;
EGPhase eg_phase_;
uint ms_;
uint tl_;
uint tl_latch_;
uint ar_;
uint dr_;
uint sr_;
uint sl_;
uint rr_;
uint ks_;
uint ssg_type_;
bool keyon_;
bool amon_;
bool param_changed_;
bool mute_;
bool inverted_;
bool held_;
};
class Operator
{
public:
Operator();
void SetChip(Chip* chip) { chip_ = chip; }
static void MakeTimeTable(uint ratio);
ISample Calc(ISample in);
ISample CalcL(ISample in);
ISample CalcFB(uint fb);
ISample CalcFBL(uint fb);
ISample CalcN(uint noise);
void Prepare();
void KeyOn();
void KeyOff();
void Reset();
void ResetFB();
int IsOn();
void SetDT(uint dt);
void SetDT2(uint dt2);
void SetMULTI(uint multi);
void SetTL(uint tl, bool csm);
void SetKS(uint ks);
void SetAR(uint ar);
void SetDR(uint dr);
void SetSR(uint sr);
void SetRR(uint rr);
void SetSL(uint sl);
void SetSSGEC(uint ssgec);
void SetFNum(uint fnum);
void SetDPBN(uint dp, uint bn);
void SetMode(bool modulator);
void SetAMON(bool on);
void SetMS(uint ms);
void Mute(bool);
// static void SetAML(uint l);
// static void SetPML(uint l);
int Out() { return out_; }
int dbgGetIn2() { return in2_; }
void dbgStopPG() { pg_diff_ = 0; pg_diff_lfo_ = 0; }
void DataSave(struct OperatorData* data);
void DataLoad(struct OperatorData* data);
private:
typedef uint32 Counter;
Chip* chip_;
ISample out_, out2_;
ISample in2_;
// Phase Generator ------------------------------------------------------
uint32 PGCalc();
uint32 PGCalcL();
uint dp_; // ΔP
uint detune_; // Detune
uint detune2_; // DT2
uint multiple_; // Multiple
uint32 pg_count_; // Phase 現在値
uint32 pg_diff_; // Phase 差分値
int32 pg_diff_lfo_; // Phase 差分値 >> x
// Envelop Generator ---------------------------------------------------
void EGCalc();
void EGStep();
void ShiftPhase(EGPhase nextphase);
void SSGShiftPhase(int mode);
void SetEGRate(uint);
void EGUpdate();
int FBCalc(int fb);
ISample LogToLin(uint a);
OpType type_; // OP の種類 (M, N...)
uint bn_; // Block/Note
int eg_level_; // EG の出力値
int eg_level_on_next_phase_; // 次の eg_phase_ に移る値
int eg_count_; // EG の次の変移までの時間
int eg_count_diff_; // eg_count_ の差分
int eg_out_; // EG+TL を合わせた出力値
int tl_out_; // TL 分の出力値
// int pm_depth_; // PM depth
// int am_depth_; // AM depth
int eg_rate_;
int eg_curve_count_;
#if 0 // libOPNMIDI: experimental SSG-EG
int ssg_offset_;
int ssg_vector_;
int ssg_phase_;
#endif
uint key_scale_rate_; // key scale rate
EGPhase eg_phase_;
uint* ams_;
uint ms_;
uint tl_; // Total Level (0-127)
uint tl_latch_; // Total Level Latch (for CSM mode)
uint ar_; // Attack Rate (0-63)
uint dr_; // Decay Rate (0-63)
uint sr_; // Sustain Rate (0-63)
uint sl_; // Sustain Level (0-127)
uint rr_; // Release Rate (0-63)
uint ks_; // Keyscale (0-3)
uint ssg_type_; // SSG-Type Envelop Control
bool keyon_;
bool amon_; // enable Amplitude Modulation
bool param_changed_; // パラメータが更新された
bool mute_;
bool inverted_;
bool held_;
// Tables ---------------------------------------------------------------
static Counter rate_table[16];
static uint32 multable[4][16];
static const uint8 notetable[128];
static const int8 dttable[256];
static const int8 decaytable1[64][8];
static const int decaytable2[16];
static const int8 attacktable[64][8];
static const int ssgenvtable[8][2][3][2];
static uint sinetable[1024];
static int32 cltable[FM_CLENTS];
static bool tablehasmade;
static void MakeTable();
// friends --------------------------------------------------------------
friend class Channel4;
public:
int dbgopout_;
int dbgpgout_;
static const int32* dbgGetClTable() { return cltable; }
static const uint* dbgGetSineTable() { return sinetable; }
};
// 4-op Channel ---------------------------------------------------------
struct Channel4Data {
uint fb;
int buf[4];
int algo_;
struct OperatorData op[4];
};
class Channel4
{
public:
Channel4();
void SetChip(Chip* chip);
void SetType(OpType type);
ISample Calc();
ISample CalcL();
ISample CalcN(uint noise);
ISample CalcLN(uint noise);
void SetFNum(uint fnum);
void SetFB(uint fb);
void SetKCKF(uint kc, uint kf);
void SetAlgorithm(uint algo);
int Prepare();
void KeyControl(uint key);
void Reset();
void SetMS(uint ms);
void Mute(bool);
void Refresh();
void dbgStopPG() { for (int i=0; i<4; i++) op[i].dbgStopPG(); }
void DataSave(struct Channel4Data* data);
void DataLoad(struct Channel4Data* data);
private:
static const uint8 fbtable[8];
uint fb;
int buf[4];
int* in[3]; // 各 OP の入力ポインタ
int* out[3]; // 各 OP の出力ポインタ
int* pms;
int algo_;
Chip* chip_;
static void MakeTable();
static bool tablehasmade;
static int kftable[64];
public:
Operator op[4];
};
// Chip resource
struct ChipData {
uint ratio_;
uint aml_;
uint pml_;
int pmv_;
OpType optype_;
uint32 multable_[4][16];
};
class Chip
{
public:
Chip();
void SetRatio(uint ratio);
void SetAML(uint l);
void SetPML(uint l);
void SetPMV(int pmv) { pmv_ = pmv; }
uint32 GetMulValue(uint dt2, uint mul) { return multable_[dt2][mul]; }
uint GetAML() { return aml_; }
uint GetPML() { return pml_; }
int GetPMV() { return pmv_; }
uint GetRatio() { return ratio_; }
void DataSave(struct ChipData* data);
void DataLoad(struct ChipData* data);
private:
void MakeTable();
uint ratio_;
uint aml_;
uint pml_;
int pmv_;
// OpType optype_;
uint32 multable_[4][16];
};
}
#endif // FM_GEN_H
// ---------------------------------------------------------------------------
// FM Sound Generator
// Copyright (C) cisc 1998, 2001.
// ---------------------------------------------------------------------------
// $Id: fmgen.h,v 1.37 2003/08/25 13:33:11 cisc Exp $
#ifndef FM_GEN_H
#define FM_GEN_H
#include "fmgen_types.h"
// ---------------------------------------------------------------------------
// 出力サンプルの型
//
// libOPNMIDI: change int32 to int16
#define FM_SAMPLETYPE int16 // int16 or int32
// ---------------------------------------------------------------------------
// 定数その1
// 静的テーブルのサイズ
#define FM_LFOBITS 8 // 変更不可
#define FM_TLBITS 7
// ---------------------------------------------------------------------------
#define FM_TLENTS (1 << FM_TLBITS)
#define FM_LFOENTS (1 << FM_LFOBITS)
#define FM_TLPOS (FM_TLENTS/4)
// サイン波の精度は 2^(1/256)
#define FM_CLENTS (0x1000 * 2) // sin + TL + LFO
// ---------------------------------------------------------------------------
namespace FM
{
// Types ----------------------------------------------------------------
typedef FM_SAMPLETYPE Sample;
typedef int32 ISample;
enum OpType { typeN=0, typeM=1 };
enum EGPhase { next, attack, decay, sustain, release, off };
void StoreSample(ISample& dest, int data);
class Chip;
struct ChipData;
// Operator -------------------------------------------------------------
struct OperatorData {
ISample out_;
ISample out2_;
ISample in2_;
uint dp_;
uint detune_;
uint detune2_;
uint multiple_;
uint32 pg_count_;
uint32 pg_diff_;
int32 pg_diff_lfo_;
OpType type_;
uint bn_;
int eg_level_;
int eg_level_on_next_phase_;
int eg_count_;
int eg_count_diff_;
int eg_out_;
int tl_out_;
int eg_rate_;
int eg_curve_count_;
#if 0 // libOPNMIDI: experimental SSG-EG
int ssg_offset_;
int ssg_vector_;
int ssg_phase_;
#endif
uint key_scale_rate_;
EGPhase eg_phase_;
uint ms_;
uint tl_;
uint tl_latch_;
uint ar_;
uint dr_;
uint sr_;
uint sl_;
uint rr_;
uint ks_;
uint ssg_type_;
bool keyon_;
bool amon_;
bool param_changed_;
bool mute_;
bool inverted_;
bool held_;
};
class Operator
{
public:
Operator();
void SetChip(Chip* chip) { chip_ = chip; }
static void MakeTimeTable(uint ratio);
ISample Calc(ISample in);
ISample CalcL(ISample in);
ISample CalcFB(uint fb);
ISample CalcFBL(uint fb);
ISample CalcN(uint noise);
void Prepare();
void KeyOn();
void KeyOff();
void Reset();
void ResetFB();
int IsOn();
void SetDT(uint dt);
void SetDT2(uint dt2);
void SetMULTI(uint multi);
void SetTL(uint tl, bool csm);
void SetKS(uint ks);
void SetAR(uint ar);
void SetDR(uint dr);
void SetSR(uint sr);
void SetRR(uint rr);
void SetSL(uint sl);
void SetSSGEC(uint ssgec);
void SetFNum(uint fnum);
void SetDPBN(uint dp, uint bn);
void SetMode(bool modulator);
void SetAMON(bool on);
void SetMS(uint ms);
void Mute(bool);
// static void SetAML(uint l);
// static void SetPML(uint l);
int Out() { return out_; }
int dbgGetIn2() { return in2_; }
void dbgStopPG() { pg_diff_ = 0; pg_diff_lfo_ = 0; }
void DataSave(struct OperatorData* data);
void DataLoad(struct OperatorData* data);
private:
typedef uint32 Counter;
Chip* chip_;
ISample out_, out2_;
ISample in2_;
// Phase Generator ------------------------------------------------------
uint32 PGCalc();
uint32 PGCalcL();
uint dp_; // ΔP
uint detune_; // Detune
uint detune2_; // DT2
uint multiple_; // Multiple
uint32 pg_count_; // Phase 現在値
uint32 pg_diff_; // Phase 差分値
int32 pg_diff_lfo_; // Phase 差分値 >> x
// Envelop Generator ---------------------------------------------------
void EGCalc();
void EGStep();
void ShiftPhase(EGPhase nextphase);
void SSGShiftPhase(int mode);
void SetEGRate(uint);
void EGUpdate();
int FBCalc(int fb);
ISample LogToLin(uint a);
OpType type_; // OP の種類 (M, N...)
uint bn_; // Block/Note
int eg_level_; // EG の出力値
int eg_level_on_next_phase_; // 次の eg_phase_ に移る値
int eg_count_; // EG の次の変移までの時間
int eg_count_diff_; // eg_count_ の差分
int eg_out_; // EG+TL を合わせた出力値
int tl_out_; // TL 分の出力値
// int pm_depth_; // PM depth
// int am_depth_; // AM depth
int eg_rate_;
int eg_curve_count_;
#if 0 // libOPNMIDI: experimental SSG-EG
int ssg_offset_;
int ssg_vector_;
int ssg_phase_;
#endif
uint key_scale_rate_; // key scale rate
EGPhase eg_phase_;
uint* ams_;
uint ms_;
uint tl_; // Total Level (0-127)
uint tl_latch_; // Total Level Latch (for CSM mode)
uint ar_; // Attack Rate (0-63)
uint dr_; // Decay Rate (0-63)
uint sr_; // Sustain Rate (0-63)
uint sl_; // Sustain Level (0-127)
uint rr_; // Release Rate (0-63)
uint ks_; // Keyscale (0-3)
uint ssg_type_; // SSG-Type Envelop Control
bool keyon_;
bool amon_; // enable Amplitude Modulation
bool param_changed_; // パラメータが更新された
bool mute_;
bool inverted_;
bool held_;
// Tables ---------------------------------------------------------------
static Counter rate_table[16];
static uint32 multable[4][16];
static const uint8 notetable[128];
static const int8 dttable[256];
static const int8 decaytable1[64][8];
static const int decaytable2[16];
static const int8 attacktable[64][8];
static const int ssgenvtable[8][2][3][2];
static uint sinetable[1024];
static int32 cltable[FM_CLENTS];
static bool tablehasmade;
static void MakeTable();
// friends --------------------------------------------------------------
friend class Channel4;
public:
int dbgopout_;
int dbgpgout_;
static const int32* dbgGetClTable() { return cltable; }
static const uint* dbgGetSineTable() { return sinetable; }
};
// 4-op Channel ---------------------------------------------------------
struct Channel4Data {
uint fb;
int buf[4];
int algo_;
struct OperatorData op[4];
};
class Channel4
{
public:
Channel4();
void SetChip(Chip* chip);
void SetType(OpType type);
ISample Calc();
ISample CalcL();
ISample CalcN(uint noise);
ISample CalcLN(uint noise);
void SetFNum(uint fnum);
void SetFB(uint fb);
void SetKCKF(uint kc, uint kf);
void SetAlgorithm(uint algo);
int Prepare();
void KeyControl(uint key);
void Reset();
void SetMS(uint ms);
void Mute(bool);
void Refresh();
void dbgStopPG() { for (int i=0; i<4; i++) op[i].dbgStopPG(); }
void DataSave(struct Channel4Data* data);
void DataLoad(struct Channel4Data* data);
private:
static const uint8 fbtable[8];
uint fb;
int buf[4];
int* in[3]; // 各 OP の入力ポインタ
int* out[3]; // 各 OP の出力ポインタ
int* pms;
int algo_;
Chip* chip_;
static void MakeTable();
static bool tablehasmade;
static int kftable[64];
public:
Operator op[4];
};
// Chip resource
struct ChipData {
uint ratio_;
uint aml_;
uint pml_;
int pmv_;
OpType optype_;
uint32 multable_[4][16];
};
class Chip
{
public:
Chip();
void SetRatio(uint ratio);
void SetAML(uint l);
void SetPML(uint l);
void SetPMV(int pmv) { pmv_ = pmv; }
uint32 GetMulValue(uint dt2, uint mul) { return multable_[dt2][mul]; }
uint GetAML() { return aml_; }
uint GetPML() { return pml_; }
int GetPMV() { return pmv_; }
uint GetRatio() { return ratio_; }
void DataSave(struct ChipData* data);
void DataLoad(struct ChipData* data);
private:
void MakeTable();
uint ratio_;
uint aml_;
uint pml_;
int pmv_;
// OpType optype_;
uint32 multable_[4][16];
};
}
#endif // FM_GEN_H

View file

@ -1,274 +1,274 @@
// ---------------------------------------------------------------------------
// FM Sound Generator
// Copyright (C) cisc 1998, 2003.
// ---------------------------------------------------------------------------
// $Id: fmgeninl.h,v 1.26 2003/06/12 13:14:36 cisc Exp $
#ifndef FM_GEN_INL_H
#define FM_GEN_INL_H
// ---------------------------------------------------------------------------
// 定数その2
//
#define FM_PI 3.14159265358979323846
#define FM_SINEPRESIS 2 // EGとサイン波の精度の差 0(低)-2(高)
#define FM_OPSINBITS 10
#define FM_OPSINENTS (1 << FM_OPSINBITS)
#define FM_EGCBITS 18 // eg の count のシフト値
#define FM_LFOCBITS 14
#ifdef FM_TUNEBUILD
#define FM_PGBITS 2
#define FM_RATIOBITS 0
#else
#define FM_PGBITS 9
#define FM_RATIOBITS 7 // 8-12 くらいまで?
#endif
#define FM_EGBITS 16
//extern int paramcount[];
//#define PARAMCHANGE(i) paramcount[i]++;
#define PARAMCHANGE(i)
namespace FM
{
// ---------------------------------------------------------------------------
// Operator
//
// フィードバックバッファをクリア
inline void Operator::ResetFB()
{
out_ = out2_ = 0;
}
// キーオン
inline void Operator::KeyOn()
{
if (!keyon_)
{
keyon_ = true;
held_ = false;
if (eg_phase_ == off || eg_phase_ == release)
{
#if 1 // libOPNMIDI: experimental SSG-EG
inverted_ = (ssg_type_ & 4) != 0;
inverted_ ^= (ssg_type_ & 2) && ar_ != 62; // try to match polarity with nuked OPN
#else
ssg_phase_ = -1;
#endif
ShiftPhase(attack);
EGUpdate();
in2_ = out_ = out2_ = 0;
pg_count_ = 0;
}
}
}
// キーオフ
inline void Operator::KeyOff()
{
if (keyon_)
{
keyon_ = false;
ShiftPhase(release);
}
}
// オペレータは稼働中か?
inline int Operator::IsOn()
{
return eg_phase_ - off;
}
// Detune (0-7)
inline void Operator::SetDT(uint dt)
{
detune_ = dt * 0x20, param_changed_ = true;
PARAMCHANGE(4);
}
// DT2 (0-3)
inline void Operator::SetDT2(uint dt2)
{
detune2_ = dt2 & 3, param_changed_ = true;
PARAMCHANGE(5);
}
// Multiple (0-15)
inline void Operator::SetMULTI(uint mul)
{
multiple_ = mul, param_changed_ = true;
PARAMCHANGE(6);
}
// Total Level (0-127) (0.75dB step)
inline void Operator::SetTL(uint tl, bool csm)
{
if (!csm)
{
tl_ = tl, param_changed_ = true;
PARAMCHANGE(7);
}
tl_latch_ = tl;
}
// Attack Rate (0-63)
inline void Operator::SetAR(uint ar)
{
ar_ = ar;
param_changed_ = true;
PARAMCHANGE(8);
}
// Decay Rate (0-63)
inline void Operator::SetDR(uint dr)
{
dr_ = dr;
param_changed_ = true;
PARAMCHANGE(9);
}
// Sustain Rate (0-63)
inline void Operator::SetSR(uint sr)
{
sr_ = sr;
param_changed_ = true;
PARAMCHANGE(10);
}
// Sustain Level (0-127)
inline void Operator::SetSL(uint sl)
{
sl_ = sl;
param_changed_ = true;
PARAMCHANGE(11);
}
// Release Rate (0-63)
inline void Operator::SetRR(uint rr)
{
rr_ = rr;
param_changed_ = true;
PARAMCHANGE(12);
}
// Keyscale (0-3)
inline void Operator::SetKS(uint ks)
{
ks_ = ks;
param_changed_ = true;
PARAMCHANGE(13);
}
// SSG-type Envelop (0-15)
inline void Operator::SetSSGEC(uint ssgec)
{
if (ssgec & 8)
ssg_type_ = ssgec;
else
ssg_type_ = 0;
}
inline void Operator::SetAMON(bool amon)
{
amon_ = amon;
param_changed_ = true;
PARAMCHANGE(14);
}
inline void Operator::Mute(bool mute)
{
mute_ = mute;
param_changed_ = true;
PARAMCHANGE(15);
}
inline void Operator::SetMS(uint ms)
{
ms_ = ms;
param_changed_ = true;
PARAMCHANGE(16);
}
// ---------------------------------------------------------------------------
// 4-op Channel
// オペレータの種類 (LFO) を設定
inline void Channel4::SetType(OpType type)
{
for (int i=0; i<4; i++)
op[i].type_ = type;
}
// セルフ・フィードバックレートの設定 (0-7)
inline void Channel4::SetFB(uint feedback)
{
fb = fbtable[feedback];
}
// OPNA 系 LFO の設定
inline void Channel4::SetMS(uint ms)
{
op[0].SetMS(ms);
op[1].SetMS(ms);
op[2].SetMS(ms);
op[3].SetMS(ms);
}
// チャンネル・マスク
inline void Channel4::Mute(bool m)
{
for (int i=0; i<4; i++)
op[i].Mute(m);
}
// 内部パラメータを再計算
inline void Channel4::Refresh()
{
for (int i=0; i<4; i++)
op[i].param_changed_ = true;
PARAMCHANGE(3);
}
inline void Channel4::SetChip(Chip* chip)
{
chip_ = chip;
for (int i=0; i<4; i++)
op[i].SetChip(chip);
}
// ---------------------------------------------------------------------------
//
//
inline void StoreSample(Sample& dest, ISample data)
{
if (sizeof(Sample) == 2)
dest = (Sample) Limit(dest + data, 0x7fff, -0x8000);
else
dest += data;
}
// ---------------------------------------------------------------------------
// AM のレベルを設定
inline void Chip::SetAML(uint l)
{
aml_ = l & (FM_LFOENTS - 1);
}
// PM のレベルを設定
inline void Chip::SetPML(uint l)
{
pml_ = l & (FM_LFOENTS - 1);
}
}
#endif // FM_GEN_INL_H
// ---------------------------------------------------------------------------
// FM Sound Generator
// Copyright (C) cisc 1998, 2003.
// ---------------------------------------------------------------------------
// $Id: fmgeninl.h,v 1.26 2003/06/12 13:14:36 cisc Exp $
#ifndef FM_GEN_INL_H
#define FM_GEN_INL_H
// ---------------------------------------------------------------------------
// 定数その2
//
#define FM_PI 3.14159265358979323846
#define FM_SINEPRESIS 2 // EGとサイン波の精度の差 0(低)-2(高)
#define FM_OPSINBITS 10
#define FM_OPSINENTS (1 << FM_OPSINBITS)
#define FM_EGCBITS 18 // eg の count のシフト値
#define FM_LFOCBITS 14
#ifdef FM_TUNEBUILD
#define FM_PGBITS 2
#define FM_RATIOBITS 0
#else
#define FM_PGBITS 9
#define FM_RATIOBITS 7 // 8-12 くらいまで?
#endif
#define FM_EGBITS 16
//extern int paramcount[];
//#define PARAMCHANGE(i) paramcount[i]++;
#define PARAMCHANGE(i)
namespace FM
{
// ---------------------------------------------------------------------------
// Operator
//
// フィードバックバッファをクリア
inline void Operator::ResetFB()
{
out_ = out2_ = 0;
}
// キーオン
inline void Operator::KeyOn()
{
if (!keyon_)
{
keyon_ = true;
held_ = false;
if (eg_phase_ == off || eg_phase_ == release)
{
#if 1 // libOPNMIDI: experimental SSG-EG
inverted_ = (ssg_type_ & 4) != 0;
inverted_ ^= (ssg_type_ & 2) && ar_ != 62; // try to match polarity with nuked OPN
#else
ssg_phase_ = -1;
#endif
ShiftPhase(attack);
EGUpdate();
in2_ = out_ = out2_ = 0;
pg_count_ = 0;
}
}
}
// キーオフ
inline void Operator::KeyOff()
{
if (keyon_)
{
keyon_ = false;
ShiftPhase(release);
}
}
// オペレータは稼働中か?
inline int Operator::IsOn()
{
return eg_phase_ - off;
}
// Detune (0-7)
inline void Operator::SetDT(uint dt)
{
detune_ = dt * 0x20, param_changed_ = true;
PARAMCHANGE(4);
}
// DT2 (0-3)
inline void Operator::SetDT2(uint dt2)
{
detune2_ = dt2 & 3, param_changed_ = true;
PARAMCHANGE(5);
}
// Multiple (0-15)
inline void Operator::SetMULTI(uint mul)
{
multiple_ = mul, param_changed_ = true;
PARAMCHANGE(6);
}
// Total Level (0-127) (0.75dB step)
inline void Operator::SetTL(uint tl, bool csm)
{
if (!csm)
{
tl_ = tl, param_changed_ = true;
PARAMCHANGE(7);
}
tl_latch_ = tl;
}
// Attack Rate (0-63)
inline void Operator::SetAR(uint ar)
{
ar_ = ar;
param_changed_ = true;
PARAMCHANGE(8);
}
// Decay Rate (0-63)
inline void Operator::SetDR(uint dr)
{
dr_ = dr;
param_changed_ = true;
PARAMCHANGE(9);
}
// Sustain Rate (0-63)
inline void Operator::SetSR(uint sr)
{
sr_ = sr;
param_changed_ = true;
PARAMCHANGE(10);
}
// Sustain Level (0-127)
inline void Operator::SetSL(uint sl)
{
sl_ = sl;
param_changed_ = true;
PARAMCHANGE(11);
}
// Release Rate (0-63)
inline void Operator::SetRR(uint rr)
{
rr_ = rr;
param_changed_ = true;
PARAMCHANGE(12);
}
// Keyscale (0-3)
inline void Operator::SetKS(uint ks)
{
ks_ = ks;
param_changed_ = true;
PARAMCHANGE(13);
}
// SSG-type Envelop (0-15)
inline void Operator::SetSSGEC(uint ssgec)
{
if (ssgec & 8)
ssg_type_ = ssgec;
else
ssg_type_ = 0;
}
inline void Operator::SetAMON(bool amon)
{
amon_ = amon;
param_changed_ = true;
PARAMCHANGE(14);
}
inline void Operator::Mute(bool mute)
{
mute_ = mute;
param_changed_ = true;
PARAMCHANGE(15);
}
inline void Operator::SetMS(uint ms)
{
ms_ = ms;
param_changed_ = true;
PARAMCHANGE(16);
}
// ---------------------------------------------------------------------------
// 4-op Channel
// オペレータの種類 (LFO) を設定
inline void Channel4::SetType(OpType type)
{
for (int i=0; i<4; i++)
op[i].type_ = type;
}
// セルフ・フィードバックレートの設定 (0-7)
inline void Channel4::SetFB(uint feedback)
{
fb = fbtable[feedback];
}
// OPNA 系 LFO の設定
inline void Channel4::SetMS(uint ms)
{
op[0].SetMS(ms);
op[1].SetMS(ms);
op[2].SetMS(ms);
op[3].SetMS(ms);
}
// チャンネル・マスク
inline void Channel4::Mute(bool m)
{
for (int i=0; i<4; i++)
op[i].Mute(m);
}
// 内部パラメータを再計算
inline void Channel4::Refresh()
{
for (int i=0; i<4; i++)
op[i].param_changed_ = true;
PARAMCHANGE(3);
}
inline void Channel4::SetChip(Chip* chip)
{
chip_ = chip;
for (int i=0; i<4; i++)
op[i].SetChip(chip);
}
// ---------------------------------------------------------------------------
//
//
inline void StoreSample(Sample& dest, ISample data)
{
if (sizeof(Sample) == 2)
dest = (Sample) Limit(dest + data, 0x7fff, -0x8000);
else
dest += data;
}
// ---------------------------------------------------------------------------
// AM のレベルを設定
inline void Chip::SetAML(uint l)
{
aml_ = l & (FM_LFOENTS - 1);
}
// PM のレベルを設定
inline void Chip::SetPML(uint l)
{
pml_ = l & (FM_LFOENTS - 1);
}
}
#endif // FM_GEN_INL_H

View file

@ -1,217 +1,217 @@
// ---------------------------------------------------------------------------
// FM sound generator common timer module
// Copyright (C) cisc 1998, 2000.
// ---------------------------------------------------------------------------
// $Id: fmtimer.cpp,v 1.1 2000/09/08 13:45:56 cisc Exp $
#include "fmgen_headers.h"
#include "fmgen_fmtimer.h"
using namespace FM;
// ---------------------------------------------------------------------------
// タイマー制御
//
void Timer::SetTimerControl(uint data)
{
uint tmp = regtc ^ data;
regtc = uint8(data);
if (data & 0x10)
ResetStatus(1);
if (data & 0x20)
ResetStatus(2);
if (tmp & 0x01)
timera_count = (data & 1) ? timera : 0;
if (tmp & 0x02)
timerb_count = (data & 2) ? timerb : 0;
}
#if 1
// ---------------------------------------------------------------------------
// タイマーA 周期設定
//
void Timer::SetTimerA(uint addr, uint data)
{
uint tmp;
regta[addr & 1] = uint8(data);
tmp = (regta[0] << 2) + (regta[1] & 3);
timera = (1024-tmp) * timer_step;
// LOG2("Timer A = %d %d us\n", tmp, timera >> 16);
}
// ---------------------------------------------------------------------------
// タイマーB 周期設定
//
void Timer::SetTimerB(uint data)
{
timerb = (256-data) * timer_step;
// LOG2("Timer B = %d %d us\n", data, timerb >> 12);
}
// ---------------------------------------------------------------------------
// タイマー時間処理
//
bool Timer::Count(int32 us)
{
bool event = false;
if (timera_count)
{
timera_count -= us << 16;
if (timera_count <= 0)
{
event = true;
TimerA();
while (timera_count <= 0)
timera_count += timera;
if (regtc & 4)
SetStatus(1);
}
}
if (timerb_count)
{
timerb_count -= us << 12;
if (timerb_count <= 0)
{
event = true;
while (timerb_count <= 0)
timerb_count += timerb;
if (regtc & 8)
SetStatus(2);
}
}
return event;
}
// ---------------------------------------------------------------------------
// 次にタイマーが発生するまでの時間を求める
//
int32 Timer::GetNextEvent()
{
uint32 ta = ((timera_count + 0xffff) >> 16) - 1;
uint32 tb = ((timerb_count + 0xfff) >> 12) - 1;
return (ta < tb ? ta : tb) + 1;
}
// ---------------------------------------------------------------------------
void Timer::DataSave(struct TimerData* data)
{
data->status = status;
data->regtc = regtc;
data->regta[0] = regta[0];
data->regta[1] = regta[1];
data->timera = timera;
data->timera_count = timera_count;
data->timerb = timerb;
data->timerb_count = timerb_count;
data->timer_step = timer_step;
}
// ---------------------------------------------------------------------------
void Timer::DataLoad(struct TimerData* data)
{
status = data->status;
regtc = data->regtc;
regta[0] = data->regta[0];
regta[1] = data->regta[1];
timera = data->timera;
timera_count = data->timera_count;
timerb = data->timerb;
timerb_count = data->timerb_count;
timer_step = data->timer_step;
}
// ---------------------------------------------------------------------------
// タイマー基準値設定
//
void Timer::SetTimerBase(uint clock)
{
timer_step = int32(1000000. * 65536 / clock);
}
#else
// ---------------------------------------------------------------------------
// タイマーA 周期設定
//
void Timer::SetTimerA(uint addr, uint data)
{
regta[addr & 1] = uint8(data);
timera = (1024 - ((regta[0] << 2) + (regta[1] & 3))) << 16;
}
// ---------------------------------------------------------------------------
// タイマーB 周期設定
//
void Timer::SetTimerB(uint data)
{
timerb = (256-data) << (16 + 4);
}
// ---------------------------------------------------------------------------
// タイマー時間処理
//
bool Timer::Count(int32 us)
{
bool event = false;
int tick = us * timer_step;
if (timera_count)
{
timera_count -= tick;
if (timera_count <= 0)
{
event = true;
TimerA();
while (timera_count <= 0)
timera_count += timera;
if (regtc & 4)
SetStatus(1);
}
}
if (timerb_count)
{
timerb_count -= tick;
if (timerb_count <= 0)
{
event = true;
while (timerb_count <= 0)
timerb_count += timerb;
if (regtc & 8)
SetStatus(2);
}
}
return event;
}
// ---------------------------------------------------------------------------
// 次にタイマーが発生するまでの時間を求める
//
int32 Timer::GetNextEvent()
{
uint32 ta = timera_count - 1;
uint32 tb = timerb_count - 1;
uint32 t = (ta < tb ? ta : tb) + 1;
return (t+timer_step-1) / timer_step;
}
// ---------------------------------------------------------------------------
// タイマー基準値設定
//
void Timer::SetTimerBase(uint clock)
{
timer_step = clock * 1024 / 15625;
}
#endif
// ---------------------------------------------------------------------------
// FM sound generator common timer module
// Copyright (C) cisc 1998, 2000.
// ---------------------------------------------------------------------------
// $Id: fmtimer.cpp,v 1.1 2000/09/08 13:45:56 cisc Exp $
#include "fmgen_headers.h"
#include "fmgen_fmtimer.h"
using namespace FM;
// ---------------------------------------------------------------------------
// タイマー制御
//
void Timer::SetTimerControl(uint data)
{
uint tmp = regtc ^ data;
regtc = uint8(data);
if (data & 0x10)
ResetStatus(1);
if (data & 0x20)
ResetStatus(2);
if (tmp & 0x01)
timera_count = (data & 1) ? timera : 0;
if (tmp & 0x02)
timerb_count = (data & 2) ? timerb : 0;
}
#if 1
// ---------------------------------------------------------------------------
// タイマーA 周期設定
//
void Timer::SetTimerA(uint addr, uint data)
{
uint tmp;
regta[addr & 1] = uint8(data);
tmp = (regta[0] << 2) + (regta[1] & 3);
timera = (1024-tmp) * timer_step;
// LOG2("Timer A = %d %d us\n", tmp, timera >> 16);
}
// ---------------------------------------------------------------------------
// タイマーB 周期設定
//
void Timer::SetTimerB(uint data)
{
timerb = (256-data) * timer_step;
// LOG2("Timer B = %d %d us\n", data, timerb >> 12);
}
// ---------------------------------------------------------------------------
// タイマー時間処理
//
bool Timer::Count(int32 us)
{
bool event = false;
if (timera_count)
{
timera_count -= us << 16;
if (timera_count <= 0)
{
event = true;
TimerA();
while (timera_count <= 0)
timera_count += timera;
if (regtc & 4)
SetStatus(1);
}
}
if (timerb_count)
{
timerb_count -= us << 12;
if (timerb_count <= 0)
{
event = true;
while (timerb_count <= 0)
timerb_count += timerb;
if (regtc & 8)
SetStatus(2);
}
}
return event;
}
// ---------------------------------------------------------------------------
// 次にタイマーが発生するまでの時間を求める
//
int32 Timer::GetNextEvent()
{
uint32 ta = ((timera_count + 0xffff) >> 16) - 1;
uint32 tb = ((timerb_count + 0xfff) >> 12) - 1;
return (ta < tb ? ta : tb) + 1;
}
// ---------------------------------------------------------------------------
void Timer::DataSave(struct TimerData* data)
{
data->status = status;
data->regtc = regtc;
data->regta[0] = regta[0];
data->regta[1] = regta[1];
data->timera = timera;
data->timera_count = timera_count;
data->timerb = timerb;
data->timerb_count = timerb_count;
data->timer_step = timer_step;
}
// ---------------------------------------------------------------------------
void Timer::DataLoad(struct TimerData* data)
{
status = data->status;
regtc = data->regtc;
regta[0] = data->regta[0];
regta[1] = data->regta[1];
timera = data->timera;
timera_count = data->timera_count;
timerb = data->timerb;
timerb_count = data->timerb_count;
timer_step = data->timer_step;
}
// ---------------------------------------------------------------------------
// タイマー基準値設定
//
void Timer::SetTimerBase(uint clock)
{
timer_step = int32(1000000. * 65536 / clock);
}
#else
// ---------------------------------------------------------------------------
// タイマーA 周期設定
//
void Timer::SetTimerA(uint addr, uint data)
{
regta[addr & 1] = uint8(data);
timera = (1024 - ((regta[0] << 2) + (regta[1] & 3))) << 16;
}
// ---------------------------------------------------------------------------
// タイマーB 周期設定
//
void Timer::SetTimerB(uint data)
{
timerb = (256-data) << (16 + 4);
}
// ---------------------------------------------------------------------------
// タイマー時間処理
//
bool Timer::Count(int32 us)
{
bool event = false;
int tick = us * timer_step;
if (timera_count)
{
timera_count -= tick;
if (timera_count <= 0)
{
event = true;
TimerA();
while (timera_count <= 0)
timera_count += timera;
if (regtc & 4)
SetStatus(1);
}
}
if (timerb_count)
{
timerb_count -= tick;
if (timerb_count <= 0)
{
event = true;
while (timerb_count <= 0)
timerb_count += timerb;
if (regtc & 8)
SetStatus(2);
}
}
return event;
}
// ---------------------------------------------------------------------------
// 次にタイマーが発生するまでの時間を求める
//
int32 Timer::GetNextEvent()
{
uint32 ta = timera_count - 1;
uint32 tb = timerb_count - 1;
uint32 t = (ta < tb ? ta : tb) + 1;
return (t+timer_step-1) / timer_step;
}
// ---------------------------------------------------------------------------
// タイマー基準値設定
//
void Timer::SetTimerBase(uint clock)
{
timer_step = clock * 1024 / 15625;
}
#endif

View file

@ -1,67 +1,67 @@
// ---------------------------------------------------------------------------
// FM sound generator common timer module
// Copyright (C) cisc 1998, 2000.
// ---------------------------------------------------------------------------
// $Id: fmtimer.h,v 1.2 2003/04/22 13:12:53 cisc Exp $
#ifndef FM_TIMER_H
#define FM_TIMER_H
#include "fmgen_types.h"
// ---------------------------------------------------------------------------
namespace FM
{
struct TimerData {
uint8 status;
uint8 regtc;
uint8 regta[2];
int32 timera, timera_count;
int32 timerb, timerb_count;
int32 timer_step;
};
class Timer
{
public:
void Reset();
bool Count(int32 us);
int32 GetNextEvent();
void DataSave(struct TimerData* data);
void DataLoad(struct TimerData* data);
protected:
virtual void SetStatus(uint bit) = 0;
virtual void ResetStatus(uint bit) = 0;
void SetTimerBase(uint clock);
void SetTimerA(uint addr, uint data);
void SetTimerB(uint data);
void SetTimerControl(uint data);
uint8 status;
uint8 regtc;
private:
virtual void TimerA() {}
uint8 regta[2];
int32 timera, timera_count;
int32 timerb, timerb_count;
int32 timer_step;
};
// ---------------------------------------------------------------------------
// <09>‰Šú‰»
//
inline void Timer::Reset()
{
timera_count = 0;
timerb_count = 0;
}
} // namespace FM
#endif // FM_TIMER_H
// ---------------------------------------------------------------------------
// FM sound generator common timer module
// Copyright (C) cisc 1998, 2000.
// ---------------------------------------------------------------------------
// $Id: fmtimer.h,v 1.2 2003/04/22 13:12:53 cisc Exp $
#ifndef FM_TIMER_H
#define FM_TIMER_H
#include "fmgen_types.h"
// ---------------------------------------------------------------------------
namespace FM
{
struct TimerData {
uint8 status;
uint8 regtc;
uint8 regta[2];
int32 timera, timera_count;
int32 timerb, timerb_count;
int32 timer_step;
};
class Timer
{
public:
void Reset();
bool Count(int32 us);
int32 GetNextEvent();
void DataSave(struct TimerData* data);
void DataLoad(struct TimerData* data);
protected:
virtual void SetStatus(uint bit) = 0;
virtual void ResetStatus(uint bit) = 0;
void SetTimerBase(uint clock);
void SetTimerA(uint addr, uint data);
void SetTimerB(uint data);
void SetTimerControl(uint data);
uint8 status;
uint8 regtc;
private:
virtual void TimerA() {}
uint8 regta[2];
int32 timera, timera_count;
int32 timerb, timerb_count;
int32 timer_step;
};
// ---------------------------------------------------------------------------
// <09>‰Šú‰»
//
inline void Timer::Reset()
{
timera_count = 0;
timerb_count = 0;
}
} // namespace FM
#endif // FM_TIMER_H

View file

@ -1,10 +1,10 @@
#ifndef WIN_HEADERS_H
#define WIN_HEADERS_H
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>
#endif // WIN_HEADERS_H
#ifndef WIN_HEADERS_H
#define WIN_HEADERS_H
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>
#endif // WIN_HEADERS_H

View file

@ -1,69 +1,69 @@
// ---------------------------------------------------------------------------
// misc.h
// Copyright (C) cisc 1998, 1999.
// ---------------------------------------------------------------------------
// $Id: misc.h,v 1.5 2002/05/31 09:45:20 cisc Exp $
#ifndef MISC_H
#define MISC_H
inline int Max(int x, int y) { return (x > y) ? x : y; }
inline int Min(int x, int y) { return (x < y) ? x : y; }
inline int Abs(int x) { return x >= 0 ? x : -x; }
inline int Limit(int v, int max, int min)
{
return v > max ? max : (v < min ? min : v);
}
inline unsigned int BSwap(unsigned int a)
{
return (a >> 24) | ((a >> 8) & 0xff00) | ((a << 8) & 0xff0000) | (a << 24);
}
inline unsigned int NtoBCD(unsigned int a)
{
return ((a / 10) << 4) + (a % 10);
}
inline unsigned int BCDtoN(unsigned int v)
{
return (v >> 4) * 10 + (v & 15);
}
template<class T>
inline T gcd(T x, T y)
{
T t;
while (y)
{
t = x % y;
x = y;
y = t;
}
return x;
}
template<class T>
T bessel0(T x)
{
T p, r, s;
r = 1.0;
s = 1.0;
p = (x / 2.0) / s;
while (p > 1.0E-10)
{
r += p * p;
s += 1.0;
p *= (x / 2.0) / s;
}
return r;
}
#endif // MISC_H
// ---------------------------------------------------------------------------
// misc.h
// Copyright (C) cisc 1998, 1999.
// ---------------------------------------------------------------------------
// $Id: misc.h,v 1.5 2002/05/31 09:45:20 cisc Exp $
#ifndef MISC_H
#define MISC_H
inline int Max(int x, int y) { return (x > y) ? x : y; }
inline int Min(int x, int y) { return (x < y) ? x : y; }
inline int Abs(int x) { return x >= 0 ? x : -x; }
inline int Limit(int v, int max, int min)
{
return v > max ? max : (v < min ? min : v);
}
inline unsigned int BSwap(unsigned int a)
{
return (a >> 24) | ((a >> 8) & 0xff00) | ((a << 8) & 0xff0000) | (a << 24);
}
inline unsigned int NtoBCD(unsigned int a)
{
return ((a / 10) << 4) + (a % 10);
}
inline unsigned int BCDtoN(unsigned int v)
{
return (v >> 4) * 10 + (v & 15);
}
template<class T>
inline T gcd(T x, T y)
{
T t;
while (y)
{
t = x % y;
x = y;
y = t;
}
return x;
}
template<class T>
T bessel0(T x)
{
T p, r, s;
r = 1.0;
s = 1.0;
p = (x / 2.0) / s;
while (p > 1.0E-10)
{
r += p * p;
s += 1.0;
p *= (x / 2.0) / s;
}
return r;
}
#endif // MISC_H

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,395 +1,395 @@
// ---------------------------------------------------------------------------
// PSG Sound Implementation
// Copyright (C) cisc 1997, 1999.
// ---------------------------------------------------------------------------
// $Id: psg.cpp,v 1.10 2002/05/15 21:38:01 cisc Exp $
#include "fmgen_headers.h"
#include "fmgen_misc.h"
#include "fmgen_psg.h"
// ---------------------------------------------------------------------------
// コンストラクタ・デストラクタ
//
PSG::PSG()
{
SetVolume(0);
MakeNoiseTable();
Reset();
mask = 0x3f;
}
PSG::~PSG()
{
}
// ---------------------------------------------------------------------------
// PSG を初期化する(RESET)
//
void PSG::Reset()
{
for (int i=0; i<14; i++)
SetReg(i, 0);
SetReg(7, 0xff);
SetReg(14, 0xff);
SetReg(15, 0xff);
}
// ---------------------------------------------------------------------------
// クロック周波数の設定
//
void PSG::SetClock(int clock, int rate)
{
tperiodbase = int((1 << toneshift ) / 4.0 * clock / rate);
eperiodbase = int((1 << envshift ) / 4.0 * clock / rate);
nperiodbase = int((1 << noiseshift) / 4.0 * clock / rate);
// 各データの更新
int tmp;
tmp = ((reg[0] + reg[1] * 256) & 0xfff);
speriod[0] = tmp ? tperiodbase / tmp : tperiodbase;
tmp = ((reg[2] + reg[3] * 256) & 0xfff);
speriod[1] = tmp ? tperiodbase / tmp : tperiodbase;
tmp = ((reg[4] + reg[5] * 256) & 0xfff);
speriod[2] = tmp ? tperiodbase / tmp : tperiodbase;
tmp = reg[6] & 0x1f;
nperiod = tmp ? nperiodbase / tmp / 2 : nperiodbase / 2;
tmp = ((reg[11] + reg[12] * 256) & 0xffff);
eperiod = tmp ? eperiodbase / tmp : eperiodbase * 2;
}
// ---------------------------------------------------------------------------
// ノイズテーブルを作成する
//
void PSG::MakeNoiseTable()
{
if (!noisetable[0])
{
int noise = 14321;
for (int i=0; i<noisetablesize; i++)
{
int n = 0;
for (int j=0; j<32; j++)
{
n = n * 2 + (noise & 1);
noise = (noise >> 1) | (((noise << 14) ^ (noise << 16)) & 0x10000);
}
noisetable[i] = n;
}
}
}
// ---------------------------------------------------------------------------
// 出力テーブルを作成
// 素直にテーブルで持ったほうが省スペース。
//
void PSG::SetVolume(int volume)
{
double base = 0x4000 / 3.0 * pow(10.0, volume / 40.0);
for (int i=31; i>=2; i--)
{
EmitTable[i] = int(base);
base /= 1.189207115;
}
EmitTable[1] = 0;
EmitTable[0] = 0;
MakeEnvelopTable();
SetChannelMask(~mask);
}
void PSG::SetChannelMask(int c)
{
mask = ~c;
for (int i=0; i<3; i++)
olevel[i] = mask & (1 << i) ? EmitTable[(reg[8+i] & 15) * 2 + 1] : 0;
}
// ---------------------------------------------------------------------------
// エンベロープ波形テーブル
//
void PSG::MakeEnvelopTable()
{
// 0 lo 1 up 2 down 3 hi
static uint8 table1[16*2] =
{
2,0, 2,0, 2,0, 2,0, 1,0, 1,0, 1,0, 1,0,
2,2, 2,0, 2,1, 2,3, 1,1, 1,3, 1,2, 1,0,
};
static uint8 table2[4] = { 0, 0, 31, 31 };
static int8 table3[4] = { 0, 1, -1, 0 };
uint* ptr = enveloptable[0];
for (int i=0; i<16*2; i++)
{
uint8 v = table2[table1[i]];
for (int j=0; j<32; j++)
{
*ptr++ = EmitTable[v];
v += table3[table1[i]];
}
}
}
// ---------------------------------------------------------------------------
// PSG のレジスタに値をセットする
// regnum レジスタの番号 (0 - 15)
// data セットする値
//
void PSG::SetReg(uint regnum, uint8 data)
{
if (regnum < 0x10)
{
reg[regnum] = data;
switch (regnum)
{
int tmp;
case 0: // ChA Fine Tune
case 1: // ChA Coarse Tune
tmp = ((reg[0] + reg[1] * 256) & 0xfff);
speriod[0] = tmp ? tperiodbase / tmp : tperiodbase;
break;
case 2: // ChB Fine Tune
case 3: // ChB Coarse Tune
tmp = ((reg[2] + reg[3] * 256) & 0xfff);
speriod[1] = tmp ? tperiodbase / tmp : tperiodbase;
break;
case 4: // ChC Fine Tune
case 5: // ChC Coarse Tune
tmp = ((reg[4] + reg[5] * 256) & 0xfff);
speriod[2] = tmp ? tperiodbase / tmp : tperiodbase;
break;
case 6: // Noise generator control
data &= 0x1f;
nperiod = data ? nperiodbase / data : nperiodbase;
break;
case 8:
olevel[0] = mask & 1 ? EmitTable[(data & 15) * 2 + 1] : 0;
break;
case 9:
olevel[1] = mask & 2 ? EmitTable[(data & 15) * 2 + 1] : 0;
break;
case 10:
olevel[2] = mask & 4 ? EmitTable[(data & 15) * 2 + 1] : 0;
break;
case 11: // Envelop period
case 12:
tmp = ((reg[11] + reg[12] * 256) & 0xffff);
eperiod = tmp ? eperiodbase / tmp : eperiodbase * 2;
break;
case 13: // Envelop shape
ecount = 0;
envelop = enveloptable[data & 15];
break;
}
}
}
// ---------------------------------------------------------------------------
void PSG::DataSave(struct PSGData* data) {
memcpy(data->reg, reg, 16);
memcpy(data->olevel, olevel, sizeof(uint) * 6);
memcpy(data->scount, scount, sizeof(uint32) * 3);
memcpy(data->speriod, speriod, sizeof(uint32) * 3);
data->ecount = ecount;
data->eperiod = eperiod;
data->ncount = ncount;
data->nperiod = nperiod;
data->tperiodbase = tperiodbase;
data->eperiodbase = eperiodbase;
data->nperiodbase = nperiodbase;
data->volume = volume;
data->mask = mask;
}
// ---------------------------------------------------------------------------
void PSG::DataLoad(struct PSGData* data) {
memcpy(reg, data->reg, 16);
memcpy(olevel, data->olevel, sizeof(uint) * 6);
memcpy(scount, data->scount, sizeof(uint32) * 3);
memcpy(speriod, data->speriod, sizeof(uint32) * 3);
ecount = data->ecount;
eperiod = data->eperiod;
ncount = data->ncount;
nperiod = data->nperiod;
tperiodbase = data->tperiodbase;
eperiodbase = data->eperiodbase;
nperiodbase = data->nperiodbase;
volume = data->volume;
mask = data->mask;
}
// ---------------------------------------------------------------------------
//
//
inline void PSG::StoreSample(Sample& dest, int32 data)
{
if (sizeof(Sample) == 2)
dest = (Sample) Limit(dest + data, 0x7fff, -0x8000);
else
dest += data;
}
// ---------------------------------------------------------------------------
// PCM データを吐き出す(2ch)
// dest PCM データを展開するポインタ
// nsamples 展開する PCM のサンプル数
//
void PSG::Mix(Sample* dest, int nsamples)
{
uint8 chenable[3], nenable[3];
uint8 r7 = ~reg[7];
if ((r7 & 0x3f) | ((reg[8] | reg[9] | reg[10]) & 0x1f))
{
chenable[0] = (r7 & 0x01) && (speriod[0] <= (1 << toneshift));
chenable[1] = (r7 & 0x02) && (speriod[1] <= (1 << toneshift));
chenable[2] = (r7 & 0x04) && (speriod[2] <= (1 << toneshift));
nenable[0] = (r7 >> 3) & 1;
nenable[1] = (r7 >> 4) & 1;
nenable[2] = (r7 >> 5) & 1;
int noise, sample;
uint env;
uint* p1 = ((mask & 1) && (reg[ 8] & 0x10)) ? &env : &olevel[0];
uint* p2 = ((mask & 2) && (reg[ 9] & 0x10)) ? &env : &olevel[1];
uint* p3 = ((mask & 4) && (reg[10] & 0x10)) ? &env : &olevel[2];
#define SCOUNT(ch) (scount[ch] >> (toneshift+oversampling))
if (p1 != &env && p2 != &env && p3 != &env)
{
// エンベロープ無し
if ((r7 & 0x38) == 0)
{
// ノイズ無し
for (int i=0; i<nsamples; i++)
{
sample = 0;
for (int j=0; j < (1 << oversampling); j++)
{
int x, y, z;
x = (SCOUNT(0) & chenable[0]) - 1;
sample += (olevel[0] + x) ^ x;
scount[0] += speriod[0];
y = (SCOUNT(1) & chenable[1]) - 1;
sample += (olevel[1] + y) ^ y;
scount[1] += speriod[1];
z = (SCOUNT(2) & chenable[2]) - 1;
sample += (olevel[2] + z) ^ z;
scount[2] += speriod[2];
}
sample /= (1 << oversampling);
StoreSample(dest[0], sample);
StoreSample(dest[1], sample);
dest += 2;
}
}
else
{
// ノイズ有り
for (int i=0; i<nsamples; i++)
{
sample = 0;
for (int j=0; j < (1 << oversampling); j++)
{
#ifdef _M_IX86
noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
>> (ncount >> (noiseshift+oversampling+1));
#else
noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
>> (ncount >> (noiseshift+oversampling+1) & 31);
#endif
ncount += nperiod;
int x, y, z;
x = ((SCOUNT(0) & chenable[0]) | (nenable[0] & noise)) - 1; // 0 or -1
sample += (olevel[0] + x) ^ x;
scount[0] += speriod[0];
y = ((SCOUNT(1) & chenable[1]) | (nenable[1] & noise)) - 1;
sample += (olevel[1] + y) ^ y;
scount[1] += speriod[1];
z = ((SCOUNT(2) & chenable[2]) | (nenable[2] & noise)) - 1;
sample += (olevel[2] + z) ^ z;
scount[2] += speriod[2];
}
sample /= (1 << oversampling);
StoreSample(dest[0], sample);
StoreSample(dest[1], sample);
dest += 2;
}
}
// エンベロープの計算をさぼった帳尻あわせ
ecount = (ecount >> 8) + (eperiod >> (8-oversampling)) * nsamples;
if (ecount >= (1 << (envshift+6+oversampling-8)))
{
if ((reg[0x0d] & 0x0b) != 0x0a)
ecount |= (1 << (envshift+5+oversampling-8));
ecount &= (1 << (envshift+6+oversampling-8)) - 1;
}
ecount <<= 8;
}
else
{
// エンベロープあり
for (int i=0; i<nsamples; i++)
{
sample = 0;
for (int j=0; j < (1 << oversampling); j++)
{
env = envelop[ecount >> (envshift+oversampling)];
ecount += eperiod;
if (ecount >= (1 << (envshift+6+oversampling)))
{
if ((reg[0x0d] & 0x0b) != 0x0a)
ecount |= (1 << (envshift+5+oversampling));
ecount &= (1 << (envshift+6+oversampling)) - 1;
}
#ifdef _M_IX86
noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
>> (ncount >> (noiseshift+oversampling+1));
#else
noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
>> (ncount >> (noiseshift+oversampling+1) & 31);
#endif
ncount += nperiod;
int x, y, z;
x = ((SCOUNT(0) & chenable[0]) | (nenable[0] & noise)) - 1; // 0 or -1
sample += (*p1 + x) ^ x;
scount[0] += speriod[0];
y = ((SCOUNT(1) & chenable[1]) | (nenable[1] & noise)) - 1;
sample += (*p2 + y) ^ y;
scount[1] += speriod[1];
z = ((SCOUNT(2) & chenable[2]) | (nenable[2] & noise)) - 1;
sample += (*p3 + z) ^ z;
scount[2] += speriod[2];
}
sample /= (1 << oversampling);
StoreSample(dest[0], sample);
StoreSample(dest[1], sample);
dest += 2;
}
}
}
}
// ---------------------------------------------------------------------------
// テーブル
//
uint PSG::noisetable[noisetablesize] = { 0, };
int PSG::EmitTable[0x20] = { -1, };
uint PSG::enveloptable[16][64] = { {0, } };
// ---------------------------------------------------------------------------
// PSG Sound Implementation
// Copyright (C) cisc 1997, 1999.
// ---------------------------------------------------------------------------
// $Id: psg.cpp,v 1.10 2002/05/15 21:38:01 cisc Exp $
#include "fmgen_headers.h"
#include "fmgen_misc.h"
#include "fmgen_psg.h"
// ---------------------------------------------------------------------------
// コンストラクタ・デストラクタ
//
PSG::PSG()
{
SetVolume(0);
MakeNoiseTable();
Reset();
mask = 0x3f;
}
PSG::~PSG()
{
}
// ---------------------------------------------------------------------------
// PSG を初期化する(RESET)
//
void PSG::Reset()
{
for (int i=0; i<14; i++)
SetReg(i, 0);
SetReg(7, 0xff);
SetReg(14, 0xff);
SetReg(15, 0xff);
}
// ---------------------------------------------------------------------------
// クロック周波数の設定
//
void PSG::SetClock(int clock, int rate)
{
tperiodbase = int((1 << toneshift ) / 4.0 * clock / rate);
eperiodbase = int((1 << envshift ) / 4.0 * clock / rate);
nperiodbase = int((1 << noiseshift) / 4.0 * clock / rate);
// 各データの更新
int tmp;
tmp = ((reg[0] + reg[1] * 256) & 0xfff);
speriod[0] = tmp ? tperiodbase / tmp : tperiodbase;
tmp = ((reg[2] + reg[3] * 256) & 0xfff);
speriod[1] = tmp ? tperiodbase / tmp : tperiodbase;
tmp = ((reg[4] + reg[5] * 256) & 0xfff);
speriod[2] = tmp ? tperiodbase / tmp : tperiodbase;
tmp = reg[6] & 0x1f;
nperiod = tmp ? nperiodbase / tmp / 2 : nperiodbase / 2;
tmp = ((reg[11] + reg[12] * 256) & 0xffff);
eperiod = tmp ? eperiodbase / tmp : eperiodbase * 2;
}
// ---------------------------------------------------------------------------
// ノイズテーブルを作成する
//
void PSG::MakeNoiseTable()
{
if (!noisetable[0])
{
int noise = 14321;
for (int i=0; i<noisetablesize; i++)
{
int n = 0;
for (int j=0; j<32; j++)
{
n = n * 2 + (noise & 1);
noise = (noise >> 1) | (((noise << 14) ^ (noise << 16)) & 0x10000);
}
noisetable[i] = n;
}
}
}
// ---------------------------------------------------------------------------
// 出力テーブルを作成
// 素直にテーブルで持ったほうが省スペース。
//
void PSG::SetVolume(int volume)
{
double base = 0x4000 / 3.0 * pow(10.0, volume / 40.0);
for (int i=31; i>=2; i--)
{
EmitTable[i] = int(base);
base /= 1.189207115;
}
EmitTable[1] = 0;
EmitTable[0] = 0;
MakeEnvelopTable();
SetChannelMask(~mask);
}
void PSG::SetChannelMask(int c)
{
mask = ~c;
for (int i=0; i<3; i++)
olevel[i] = mask & (1 << i) ? EmitTable[(reg[8+i] & 15) * 2 + 1] : 0;
}
// ---------------------------------------------------------------------------
// エンベロープ波形テーブル
//
void PSG::MakeEnvelopTable()
{
// 0 lo 1 up 2 down 3 hi
static uint8 table1[16*2] =
{
2,0, 2,0, 2,0, 2,0, 1,0, 1,0, 1,0, 1,0,
2,2, 2,0, 2,1, 2,3, 1,1, 1,3, 1,2, 1,0,
};
static uint8 table2[4] = { 0, 0, 31, 31 };
static int8 table3[4] = { 0, 1, -1, 0 };
uint* ptr = enveloptable[0];
for (int i=0; i<16*2; i++)
{
uint8 v = table2[table1[i]];
for (int j=0; j<32; j++)
{
*ptr++ = EmitTable[v];
v += table3[table1[i]];
}
}
}
// ---------------------------------------------------------------------------
// PSG のレジスタに値をセットする
// regnum レジスタの番号 (0 - 15)
// data セットする値
//
void PSG::SetReg(uint regnum, uint8 data)
{
if (regnum < 0x10)
{
reg[regnum] = data;
switch (regnum)
{
int tmp;
case 0: // ChA Fine Tune
case 1: // ChA Coarse Tune
tmp = ((reg[0] + reg[1] * 256) & 0xfff);
speriod[0] = tmp ? tperiodbase / tmp : tperiodbase;
break;
case 2: // ChB Fine Tune
case 3: // ChB Coarse Tune
tmp = ((reg[2] + reg[3] * 256) & 0xfff);
speriod[1] = tmp ? tperiodbase / tmp : tperiodbase;
break;
case 4: // ChC Fine Tune
case 5: // ChC Coarse Tune
tmp = ((reg[4] + reg[5] * 256) & 0xfff);
speriod[2] = tmp ? tperiodbase / tmp : tperiodbase;
break;
case 6: // Noise generator control
data &= 0x1f;
nperiod = data ? nperiodbase / data : nperiodbase;
break;
case 8:
olevel[0] = mask & 1 ? EmitTable[(data & 15) * 2 + 1] : 0;
break;
case 9:
olevel[1] = mask & 2 ? EmitTable[(data & 15) * 2 + 1] : 0;
break;
case 10:
olevel[2] = mask & 4 ? EmitTable[(data & 15) * 2 + 1] : 0;
break;
case 11: // Envelop period
case 12:
tmp = ((reg[11] + reg[12] * 256) & 0xffff);
eperiod = tmp ? eperiodbase / tmp : eperiodbase * 2;
break;
case 13: // Envelop shape
ecount = 0;
envelop = enveloptable[data & 15];
break;
}
}
}
// ---------------------------------------------------------------------------
void PSG::DataSave(struct PSGData* data) {
memcpy(data->reg, reg, 16);
memcpy(data->olevel, olevel, sizeof(uint) * 6);
memcpy(data->scount, scount, sizeof(uint32) * 3);
memcpy(data->speriod, speriod, sizeof(uint32) * 3);
data->ecount = ecount;
data->eperiod = eperiod;
data->ncount = ncount;
data->nperiod = nperiod;
data->tperiodbase = tperiodbase;
data->eperiodbase = eperiodbase;
data->nperiodbase = nperiodbase;
data->volume = volume;
data->mask = mask;
}
// ---------------------------------------------------------------------------
void PSG::DataLoad(struct PSGData* data) {
memcpy(reg, data->reg, 16);
memcpy(olevel, data->olevel, sizeof(uint) * 6);
memcpy(scount, data->scount, sizeof(uint32) * 3);
memcpy(speriod, data->speriod, sizeof(uint32) * 3);
ecount = data->ecount;
eperiod = data->eperiod;
ncount = data->ncount;
nperiod = data->nperiod;
tperiodbase = data->tperiodbase;
eperiodbase = data->eperiodbase;
nperiodbase = data->nperiodbase;
volume = data->volume;
mask = data->mask;
}
// ---------------------------------------------------------------------------
//
//
inline void PSG::StoreSample(Sample& dest, int32 data)
{
if (sizeof(Sample) == 2)
dest = (Sample) Limit(dest + data, 0x7fff, -0x8000);
else
dest += data;
}
// ---------------------------------------------------------------------------
// PCM データを吐き出す(2ch)
// dest PCM データを展開するポインタ
// nsamples 展開する PCM のサンプル数
//
void PSG::Mix(Sample* dest, int nsamples)
{
uint8 chenable[3], nenable[3];
uint8 r7 = ~reg[7];
if ((r7 & 0x3f) | ((reg[8] | reg[9] | reg[10]) & 0x1f))
{
chenable[0] = (r7 & 0x01) && (speriod[0] <= (1 << toneshift));
chenable[1] = (r7 & 0x02) && (speriod[1] <= (1 << toneshift));
chenable[2] = (r7 & 0x04) && (speriod[2] <= (1 << toneshift));
nenable[0] = (r7 >> 3) & 1;
nenable[1] = (r7 >> 4) & 1;
nenable[2] = (r7 >> 5) & 1;
int noise, sample;
uint env;
uint* p1 = ((mask & 1) && (reg[ 8] & 0x10)) ? &env : &olevel[0];
uint* p2 = ((mask & 2) && (reg[ 9] & 0x10)) ? &env : &olevel[1];
uint* p3 = ((mask & 4) && (reg[10] & 0x10)) ? &env : &olevel[2];
#define SCOUNT(ch) (scount[ch] >> (toneshift+oversampling))
if (p1 != &env && p2 != &env && p3 != &env)
{
// エンベロープ無し
if ((r7 & 0x38) == 0)
{
// ノイズ無し
for (int i=0; i<nsamples; i++)
{
sample = 0;
for (int j=0; j < (1 << oversampling); j++)
{
int x, y, z;
x = (SCOUNT(0) & chenable[0]) - 1;
sample += (olevel[0] + x) ^ x;
scount[0] += speriod[0];
y = (SCOUNT(1) & chenable[1]) - 1;
sample += (olevel[1] + y) ^ y;
scount[1] += speriod[1];
z = (SCOUNT(2) & chenable[2]) - 1;
sample += (olevel[2] + z) ^ z;
scount[2] += speriod[2];
}
sample /= (1 << oversampling);
StoreSample(dest[0], sample);
StoreSample(dest[1], sample);
dest += 2;
}
}
else
{
// ノイズ有り
for (int i=0; i<nsamples; i++)
{
sample = 0;
for (int j=0; j < (1 << oversampling); j++)
{
#ifdef _M_IX86
noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
>> (ncount >> (noiseshift+oversampling+1));
#else
noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
>> (ncount >> (noiseshift+oversampling+1) & 31);
#endif
ncount += nperiod;
int x, y, z;
x = ((SCOUNT(0) & chenable[0]) | (nenable[0] & noise)) - 1; // 0 or -1
sample += (olevel[0] + x) ^ x;
scount[0] += speriod[0];
y = ((SCOUNT(1) & chenable[1]) | (nenable[1] & noise)) - 1;
sample += (olevel[1] + y) ^ y;
scount[1] += speriod[1];
z = ((SCOUNT(2) & chenable[2]) | (nenable[2] & noise)) - 1;
sample += (olevel[2] + z) ^ z;
scount[2] += speriod[2];
}
sample /= (1 << oversampling);
StoreSample(dest[0], sample);
StoreSample(dest[1], sample);
dest += 2;
}
}
// エンベロープの計算をさぼった帳尻あわせ
ecount = (ecount >> 8) + (eperiod >> (8-oversampling)) * nsamples;
if (ecount >= (1 << (envshift+6+oversampling-8)))
{
if ((reg[0x0d] & 0x0b) != 0x0a)
ecount |= (1 << (envshift+5+oversampling-8));
ecount &= (1 << (envshift+6+oversampling-8)) - 1;
}
ecount <<= 8;
}
else
{
// エンベロープあり
for (int i=0; i<nsamples; i++)
{
sample = 0;
for (int j=0; j < (1 << oversampling); j++)
{
env = envelop[ecount >> (envshift+oversampling)];
ecount += eperiod;
if (ecount >= (1 << (envshift+6+oversampling)))
{
if ((reg[0x0d] & 0x0b) != 0x0a)
ecount |= (1 << (envshift+5+oversampling));
ecount &= (1 << (envshift+6+oversampling)) - 1;
}
#ifdef _M_IX86
noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
>> (ncount >> (noiseshift+oversampling+1));
#else
noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
>> (ncount >> (noiseshift+oversampling+1) & 31);
#endif
ncount += nperiod;
int x, y, z;
x = ((SCOUNT(0) & chenable[0]) | (nenable[0] & noise)) - 1; // 0 or -1
sample += (*p1 + x) ^ x;
scount[0] += speriod[0];
y = ((SCOUNT(1) & chenable[1]) | (nenable[1] & noise)) - 1;
sample += (*p2 + y) ^ y;
scount[1] += speriod[1];
z = ((SCOUNT(2) & chenable[2]) | (nenable[2] & noise)) - 1;
sample += (*p3 + z) ^ z;
scount[2] += speriod[2];
}
sample /= (1 << oversampling);
StoreSample(dest[0], sample);
StoreSample(dest[1], sample);
dest += 2;
}
}
}
}
// ---------------------------------------------------------------------------
// テーブル
//
uint PSG::noisetable[noisetablesize] = { 0, };
int PSG::EmitTable[0x20] = { -1, };
uint PSG::enveloptable[16][64] = { {0, } };

View file

@ -1,115 +1,115 @@
// ---------------------------------------------------------------------------
// PSG-like sound generator
// Copyright (C) cisc 1997, 1999.
// ---------------------------------------------------------------------------
// $Id: psg.h,v 1.8 2003/04/22 13:12:53 cisc Exp $
#ifndef PSG_H
#define PSG_H
#include "fmgen_types.h"
// libOPNMIDI: change int32 to int16
#define PSG_SAMPLETYPE int16 // int32 or int16
// ---------------------------------------------------------------------------
// class PSG
// PSG に良く似た音を生成する音源ユニット
//
// interface:
// bool SetClock(uint clock, uint rate)
// 初期化.このクラスを使用する前にかならず呼んでおくこと.
// PSG のクロックや PCM レートを設定する
//
// clock: PSG の動作クロック
// rate: 生成する PCM のレート
// retval 初期化に成功すれば true
//
// void Mix(Sample* dest, int nsamples)
// PCM を nsamples 分合成し, dest で始まる配列に加える(加算する)
// あくまで加算なので,最初に配列をゼロクリアする必要がある
//
// void Reset()
// リセットする
//
// void SetReg(uint reg, uint8 data)
// レジスタ reg に data を書き込む
//
// uint GetReg(uint reg)
// レジスタ reg の内容を読み出す
//
// void SetVolume(int db)
// 各音源の音量を調節する
// 単位は約 1/2 dB
//
struct PSGData {
uint8 reg[16];
uint olevel[3];
uint32 scount[3];
uint32 speriod[3];
uint32 ecount;
uint32 eperiod;
uint32 ncount;
uint32 nperiod;
uint32 tperiodbase;
uint32 eperiodbase;
uint32 nperiodbase;
int volume;
int mask;
};
class PSG
{
public:
typedef PSG_SAMPLETYPE Sample;
enum
{
noisetablesize = 1 << 11, // ←メモリ使用量を減らしたいなら減らして
toneshift = 24,
envshift = 22,
noiseshift = 14,
oversampling = 2 // ← 音質より速度が優先なら減らすといいかも
};
public:
PSG();
~PSG();
void Mix(Sample* dest, int nsamples);
void SetClock(int clock, int rate);
void SetVolume(int vol);
void SetChannelMask(int c);
void Reset();
void SetReg(uint regnum, uint8 data);
uint GetReg(uint regnum) { return reg[regnum & 0x0f]; }
void DataSave(struct PSGData* data);
void DataLoad(struct PSGData* data);
protected:
void MakeNoiseTable();
void MakeEnvelopTable();
static void StoreSample(Sample& dest, int32 data);
uint8 reg[16];
const uint* envelop;
uint olevel[3];
uint32 scount[3], speriod[3];
uint32 ecount, eperiod;
uint32 ncount, nperiod;
uint32 tperiodbase;
uint32 eperiodbase;
uint32 nperiodbase;
int volume;
int mask;
static uint enveloptable[16][64];
static uint noisetable[noisetablesize];
static int EmitTable[32];
};
#endif // PSG_H
// ---------------------------------------------------------------------------
// PSG-like sound generator
// Copyright (C) cisc 1997, 1999.
// ---------------------------------------------------------------------------
// $Id: psg.h,v 1.8 2003/04/22 13:12:53 cisc Exp $
#ifndef PSG_H
#define PSG_H
#include "fmgen_types.h"
// libOPNMIDI: change int32 to int16
#define PSG_SAMPLETYPE int16 // int32 or int16
// ---------------------------------------------------------------------------
// class PSG
// PSG に良く似た音を生成する音源ユニット
//
// interface:
// bool SetClock(uint clock, uint rate)
// 初期化.このクラスを使用する前にかならず呼んでおくこと.
// PSG のクロックや PCM レートを設定する
//
// clock: PSG の動作クロック
// rate: 生成する PCM のレート
// retval 初期化に成功すれば true
//
// void Mix(Sample* dest, int nsamples)
// PCM を nsamples 分合成し, dest で始まる配列に加える(加算する)
// あくまで加算なので,最初に配列をゼロクリアする必要がある
//
// void Reset()
// リセットする
//
// void SetReg(uint reg, uint8 data)
// レジスタ reg に data を書き込む
//
// uint GetReg(uint reg)
// レジスタ reg の内容を読み出す
//
// void SetVolume(int db)
// 各音源の音量を調節する
// 単位は約 1/2 dB
//
struct PSGData {
uint8 reg[16];
uint olevel[3];
uint32 scount[3];
uint32 speriod[3];
uint32 ecount;
uint32 eperiod;
uint32 ncount;
uint32 nperiod;
uint32 tperiodbase;
uint32 eperiodbase;
uint32 nperiodbase;
int volume;
int mask;
};
class PSG
{
public:
typedef PSG_SAMPLETYPE Sample;
enum
{
noisetablesize = 1 << 11, // ←メモリ使用量を減らしたいなら減らして
toneshift = 24,
envshift = 22,
noiseshift = 14,
oversampling = 2 // ← 音質より速度が優先なら減らすといいかも
};
public:
PSG();
~PSG();
void Mix(Sample* dest, int nsamples);
void SetClock(int clock, int rate);
void SetVolume(int vol);
void SetChannelMask(int c);
void Reset();
void SetReg(uint regnum, uint8 data);
uint GetReg(uint regnum) { return reg[regnum & 0x0f]; }
void DataSave(struct PSGData* data);
void DataLoad(struct PSGData* data);
protected:
void MakeNoiseTable();
void MakeEnvelopTable();
static void StoreSample(Sample& dest, int32 data);
uint8 reg[16];
const uint* envelop;
uint olevel[3];
uint32 scount[3], speriod[3];
uint32 ecount, eperiod;
uint32 ncount, nperiod;
uint32 tperiodbase;
uint32 eperiodbase;
uint32 nperiodbase;
int volume;
int mask;
static uint enveloptable[16][64];
static uint noisetable[noisetablesize];
static int EmitTable[32];
};
#endif // PSG_H

View file

@ -1,93 +1,93 @@
------------------------------------------------------------------------------
FM Sound Generator with OPN/OPM interface
Copyright (C) by cisc 1998, 2003.
------------------------------------------------------------------------------
【概要】
C++ による FM/PSG 音源の実装です。
AY8910, YM2203, YM2151, YM2608, YM2610 相当のインターフェースも
実装してあります。
【使い方】
(TODO:中身を書く)
【注意】
以前のバージョンから幾分手を加えました。インターフェースは
いじっていないつもりですが、何かしらのバグが隠れているかもしれません。
YM2610 は動作チェックすらしていません。
線形補完モード(interpolation)は廃止されました。
Init() の引数仕様は変わっていませんが、interpolation = true にしても
動作は変わりません。
OPNA::Init/SetRate で与えるチップクロックの値の仕様が
以前の M88 に搭載されていたバージョンと異なっています.
【著作権、免責規定】
・本ソースコードは作者(cisc@retropc.net) が著作権を所有しています。
・本ソースコードはあるがままに提供されるものであり,
暗黙及び明示的な保証を一切含みません.
・本ソースコードを利用したこと,利用しなかったこと,
利用できなかったことに関して生じたあるいは生じると予測される
損害について,作者は一切責任を負いません.
・本ソースコードは,以下の制限を満たす限り自由に改変・組み込み・
配布・利用することができます.
1. 本ソフトの由来(作者, 著作権)を明記すること.
2. 配布する際にはフリーソフトとすること.
3. 改変したソースコードを配布する際は改変内容を明示すること.
4. ソースコードを配布する際にはこのテキストを一切改変せずに
そのまま添付すること.
・公開の際に作者への連絡を頂ければ幸いです.
・商用ソフト(シェアウェア含む) に本ソースコードの一部,または
全部を組み込む際には,事前に作者の合意を得る必要があります.
【変更点】
008 030902 ・出力サンプリングレートの設定を、チップ元来の合成サンプ
リングレートと異なる設定にするとエンベロープがおかしく
なる問題を修正。
007a 030608 ・領域外アクセスがあったのを修正 (Thanks to PI.様)
007 030607 ・再現性の向上
・OPN: SSG-EG のサポート
・線形補完の廃止
・asm 版の廃止
・マルチスレッドフリーになった?
006 010330 ・再現性に関していくらか手直し(正弦波,出力タイミング等)
005 010317 ・OPN: FM 音源の合成周波数が出力周波数よりも低いときに,
補完を使うと音痴になる/音がまともに出なくなる問題を修正.
・FM: 補完を使わない時の精度を上げてみる.
問題が起きたら fmgeninl.h の FM_RATIOBITS を 8 に戻すと吉.
004a 010311 ・OPM: ノイズをそこそこ聞けるレベル()まで修正.
・OPNA/OPM: FM_USE_CALC2 廃止.
・デグレ修正, なんのために cvs で管理しているんだか…(T-T
OPNB: ADPCMB ROM マスク作成ミス.
OPNB: ADPCMA ステータスフラグ関係の挙動修復.
OPM: LFO パラメータの初期化を忘れていたのを修正.
003 010124 ・OPNA/OPM 実際には補完前の値を出力していたバグを修正.
002 010123 ・合成周波数が出力周波数より低いときでも補間が効くようにする.
・OPN: 補間時にプリスケーラの設定を変更したときに音化けする
バグを修正.
・OPNA/B: LFO が効かないバグを修正.
001 000928 ・初期バージョン
$Id: readme.txt,v 1.1 2003/06/07 08:25:20 cisc Exp $
------------------------------------------------------------------------------
FM Sound Generator with OPN/OPM interface
Copyright (C) by cisc 1998, 2003.
------------------------------------------------------------------------------
【概要】
C++ による FM/PSG 音源の実装です。
AY8910, YM2203, YM2151, YM2608, YM2610 相当のインターフェースも
実装してあります。
【使い方】
(TODO:中身を書く)
【注意】
以前のバージョンから幾分手を加えました。インターフェースは
いじっていないつもりですが、何かしらのバグが隠れているかもしれません。
YM2610 は動作チェックすらしていません。
線形補完モード(interpolation)は廃止されました。
Init() の引数仕様は変わっていませんが、interpolation = true にしても
動作は変わりません。
OPNA::Init/SetRate で与えるチップクロックの値の仕様が
以前の M88 に搭載されていたバージョンと異なっています.
【著作権、免責規定】
・本ソースコードは作者(cisc@retropc.net) が著作権を所有しています。
・本ソースコードはあるがままに提供されるものであり,
暗黙及び明示的な保証を一切含みません.
・本ソースコードを利用したこと,利用しなかったこと,
利用できなかったことに関して生じたあるいは生じると予測される
損害について,作者は一切責任を負いません.
・本ソースコードは,以下の制限を満たす限り自由に改変・組み込み・
配布・利用することができます.
1. 本ソフトの由来(作者, 著作権)を明記すること.
2. 配布する際にはフリーソフトとすること.
3. 改変したソースコードを配布する際は改変内容を明示すること.
4. ソースコードを配布する際にはこのテキストを一切改変せずに
そのまま添付すること.
・公開の際に作者への連絡を頂ければ幸いです.
・商用ソフト(シェアウェア含む) に本ソースコードの一部,または
全部を組み込む際には,事前に作者の合意を得る必要があります.
【変更点】
008 030902 ・出力サンプリングレートの設定を、チップ元来の合成サンプ
リングレートと異なる設定にするとエンベロープがおかしく
なる問題を修正。
007a 030608 ・領域外アクセスがあったのを修正 (Thanks to PI.様)
007 030607 ・再現性の向上
・OPN: SSG-EG のサポート
・線形補完の廃止
・asm 版の廃止
・マルチスレッドフリーになった?
006 010330 ・再現性に関していくらか手直し(正弦波,出力タイミング等)
005 010317 ・OPN: FM 音源の合成周波数が出力周波数よりも低いときに,
補完を使うと音痴になる/音がまともに出なくなる問題を修正.
・FM: 補完を使わない時の精度を上げてみる.
問題が起きたら fmgeninl.h の FM_RATIOBITS を 8 に戻すと吉.
004a 010311 ・OPM: ノイズをそこそこ聞けるレベル()まで修正.
・OPNA/OPM: FM_USE_CALC2 廃止.
・デグレ修正, なんのために cvs で管理しているんだか…(T-T
OPNB: ADPCMB ROM マスク作成ミス.
OPNB: ADPCMA ステータスフラグ関係の挙動修復.
OPM: LFO パラメータの初期化を忘れていたのを修正.
003 010124 ・OPNA/OPM 実際には補完前の値を出力していたバグを修正.
002 010123 ・合成周波数が出力周波数より低いときでも補間が効くようにする.
・OPN: 補間時にプリスケーラの設定を変更したときに音化けする
バグを修正.
・OPNA/B: LFO が効かないバグを修正.
001 000928 ・初期バージョン
$Id: readme.txt,v 1.1 2003/06/07 08:25:20 cisc Exp $

View file

@ -1,23 +1,23 @@
#if !defined(win32_types_h)
#define win32_types_h
#include "compiler.h"
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef signed char sint8;
typedef signed short sint16;
typedef signed int sint32;
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
#endif // win32_types_h
#if !defined(win32_types_h)
#define win32_types_h
#include "compiler.h"
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef signed char sint8;
typedef signed short sint16;
typedef signed int sint32;
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
#endif // win32_types_h

View file

@ -288,8 +288,8 @@ endif()
# Check for functions that may or may not exist.
require_stricmp()
require_strnicmp()
gz_require_stricmp()
gz_require_strnicmp()
if( NOT MSVC )
add_definitions( -D__forceinline=inline )
@ -327,32 +327,8 @@ endif()
list( APPEND PROJECT_LIBRARIES "zwidget" )
list( APPEND PROJECT_LIBRARIES "webp" )
# ZMUSIC
if( MSVC )
find_package( ZMusic )
else()
find_package( ZMusic REQUIRED )
endif()
message("Building for target architecture: ${TARGET_ARCHITECTURE}")
if( MSVC AND NOT ZMUSIC_FOUND )
# Use prebuilt library
set( ZMUSIC_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../bin/windows/zmusic" )
set( ZMUSIC_INCLUDE_DIR ${ZMUSIC_ROOT_PATH}/include )
set( ZMUSIC_LIBRARIES zmusic )
if( X64 )
link_directories( ${ZMUSIC_ROOT_PATH}/64bit )
elseif( ARM64 )
link_directories( ${ZMUSIC_ROOT_PATH}/arm64 )
else()
link_directories( ${ZMUSIC_ROOT_PATH}/32bit )
endif()
set( ZMUSIC_FOUND TRUE )
endif()
# VPX
if( MSVC AND NOT VPX_FOUND )