diff options
Diffstat (limited to 'lib/rbcodec/codecs/libgme/nes_apu.h')
-rw-r--r-- | lib/rbcodec/codecs/libgme/nes_apu.h | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/nes_apu.h b/lib/rbcodec/codecs/libgme/nes_apu.h new file mode 100644 index 0000000000..152ec94a17 --- /dev/null +++ b/lib/rbcodec/codecs/libgme/nes_apu.h | |||
@@ -0,0 +1,137 @@ | |||
1 | // NES 2A03 APU sound chip emulator | ||
2 | |||
3 | // Nes_Snd_Emu 0.2.0-pre | ||
4 | #ifndef NES_APU_H | ||
5 | #define NES_APU_H | ||
6 | |||
7 | #include "blargg_common.h" | ||
8 | #include "nes_oscs.h" | ||
9 | |||
10 | enum { apu_status_addr = 0x4015 }; | ||
11 | enum { apu_osc_count = 5 }; | ||
12 | enum { apu_no_irq = INT_MAX/2 + 1 }; | ||
13 | enum { apu_irq_waiting = 0 }; | ||
14 | |||
15 | enum { apu_io_addr = 0x4000 }; | ||
16 | enum { apu_io_size = 0x18 }; | ||
17 | |||
18 | struct apu_state_t; | ||
19 | |||
20 | struct Nes_Apu { | ||
21 | int tempo_; | ||
22 | nes_time_t last_time; // has been run until this time in current frame | ||
23 | nes_time_t last_dmc_time; | ||
24 | nes_time_t earliest_irq_; | ||
25 | nes_time_t next_irq; | ||
26 | int frame_period; | ||
27 | int frame_delay; // cycles until frame counter runs next | ||
28 | int frame; // current frame (0-3) | ||
29 | int osc_enables; | ||
30 | int frame_mode; | ||
31 | bool irq_flag; | ||
32 | |||
33 | void (*irq_notifier_)( void* user_data ); | ||
34 | void* irq_data; | ||
35 | |||
36 | Synth square_synth; // shared by squares | ||
37 | |||
38 | struct Nes_Osc* oscs [apu_osc_count]; | ||
39 | struct Nes_Square square1; | ||
40 | struct Nes_Square square2; | ||
41 | struct Nes_Noise noise; | ||
42 | struct Nes_Triangle triangle; | ||
43 | struct Nes_Dmc dmc; | ||
44 | }; | ||
45 | |||
46 | // Init Nes apu | ||
47 | void Apu_init( struct Nes_Apu* this ); | ||
48 | |||
49 | // Set buffer to generate all sound into, or disable sound if NULL | ||
50 | void Apu_output( struct Nes_Apu* this, struct Blip_Buffer* ); | ||
51 | |||
52 | // All time values are the number of cpu clock cycles relative to the | ||
53 | // beginning of the current time frame. Before resetting the cpu clock | ||
54 | // count, call end_frame( last_cpu_time ). | ||
55 | |||
56 | // Write to register (0x4000-0x4017, except 0x4014 and 0x4016) | ||
57 | void Apu_write_register( struct Nes_Apu* this, nes_time_t, addr_t, int data ); | ||
58 | |||
59 | // Read from status register at 0x4015 | ||
60 | int Apu_read_status( struct Nes_Apu* this, nes_time_t ); | ||
61 | |||
62 | // Run all oscillators up to specified time, end current time frame, then | ||
63 | // start a new time frame at time 0. Time frames have no effect on emulation | ||
64 | // and each can be whatever length is convenient. | ||
65 | void Apu_end_frame( struct Nes_Apu* this, nes_time_t ); | ||
66 | |||
67 | // Additional optional features (can be ignored without any problem) | ||
68 | |||
69 | // Reset internal frame counter, registers, and all oscillators. | ||
70 | // Use PAL timing if pal_timing is true, otherwise use NTSC timing. | ||
71 | // Set the DMC oscillator's initial DAC value to initial_dmc_dac without | ||
72 | // any audible click. | ||
73 | void Apu_reset( struct Nes_Apu* this, bool pal_mode, int initial_dmc_dac ); | ||
74 | |||
75 | // Adjust frame period | ||
76 | void Apu_set_tempo( struct Nes_Apu* this, int ); | ||
77 | |||
78 | // Set overall volume (default is 1.0) | ||
79 | void Apu_volume( struct Nes_Apu* this, int ); | ||
80 | |||
81 | // Run DMC until specified time, so that any DMC memory reads can be | ||
82 | // accounted for (i.e. inserting cpu wait states). | ||
83 | void Apu_run_until( struct Nes_Apu* this, nes_time_t ); | ||
84 | |||
85 | // Set sound output of specific oscillator to buffer. If buffer is NULL, | ||
86 | // the specified oscillator is muted and emulation accuracy is reduced. | ||
87 | // The oscillators are indexed as follows: 0) Square 1, 1) Square 2, | ||
88 | // 2) Triangle, 3) Noise, 4) DMC. | ||
89 | static inline void Apu_osc_output( struct Nes_Apu* this, int osc, struct Blip_Buffer* buf ) | ||
90 | { | ||
91 | assert( (unsigned) osc < apu_osc_count ); | ||
92 | this->oscs [osc]->output = buf; | ||
93 | } | ||
94 | |||
95 | // Set memory reader callback used by DMC oscillator to fetch samples. | ||
96 | // When callback is invoked, 'user_data' is passed unchanged as the | ||
97 | // first parameter. | ||
98 | static inline void Apu_dmc_reader( struct Nes_Apu* this, int (*func)( void*, addr_t ), void* user_data ) | ||
99 | { | ||
100 | this->dmc.prg_reader_data = user_data; | ||
101 | this->dmc.prg_reader = func; | ||
102 | } | ||
103 | |||
104 | // Set IRQ time callback that is invoked when the time of earliest IRQ | ||
105 | // may have changed, or NULL to disable. When callback is invoked, | ||
106 | // 'user_data' is passed unchanged as the first parameter. | ||
107 | static inline void Apu_irq_notifier( struct Nes_Apu* this, void (*func)( void* user_data ), void* user_data ) | ||
108 | { | ||
109 | this->irq_notifier_ = func; | ||
110 | this->irq_data = user_data; | ||
111 | } | ||
112 | |||
113 | // Count number of DMC reads that would occur if 'run_until( t )' were executed. | ||
114 | // If last_read is not NULL, set *last_read to the earliest time that | ||
115 | // 'count_dmc_reads( time )' would result in the same result. | ||
116 | static inline int Apu_count_dmc_reads( struct Nes_Apu* this, nes_time_t time, nes_time_t* last_read ) | ||
117 | { | ||
118 | return Dmc_count_reads( &this->dmc, time, last_read ); | ||
119 | } | ||
120 | |||
121 | static inline nes_time_t Dmc_next_read_time( struct Nes_Dmc* this ) | ||
122 | { | ||
123 | if ( this->osc.length_counter == 0 ) | ||
124 | return apu_no_irq; // not reading | ||
125 | |||
126 | return this->apu->last_dmc_time + this->osc.delay + (this->bits_remain - 1) * this->period; | ||
127 | } | ||
128 | |||
129 | // Time when next DMC memory read will occur | ||
130 | static inline nes_time_t Apu_next_dmc_read_time( struct Nes_Apu* this ) { return Dmc_next_read_time( &this->dmc ); } | ||
131 | void Apu_irq_changed( struct Nes_Apu* this ); | ||
132 | |||
133 | #if 0 | ||
134 | // Experimental | ||
135 | void Apu_enable_nonlinear_( struct Nes_Apu* this, int sq, int tnd ); | ||
136 | #endif | ||
137 | #endif | ||