summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libgme/nes_vrc7_apu.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libgme/nes_vrc7_apu.c')
-rw-r--r--lib/rbcodec/codecs/libgme/nes_vrc7_apu.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/nes_vrc7_apu.c b/lib/rbcodec/codecs/libgme/nes_vrc7_apu.c
new file mode 100644
index 0000000000..8d3c2e88a6
--- /dev/null
+++ b/lib/rbcodec/codecs/libgme/nes_vrc7_apu.c
@@ -0,0 +1,88 @@
1
2#include "nes_vrc7_apu.h"
3#include "blargg_source.h"
4
5int const period = 36; // NES CPU clocks per FM clock
6
7void Vrc7_init( struct Nes_Vrc7_Apu* this )
8{
9 Synth_init( &this->synth );
10
11 OPLL_new ( &this->opll, 3579545, 3579545 / 72 );
12 OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE );
13
14 this->osc.output = 0;
15 this->osc.last_amp = 0;
16 this->mask = 0;
17
18 Vrc7_volume( this, (int)FP_ONE_VOLUME );
19 Vrc7_reset( this );
20}
21
22void Vrc7_reset( struct Nes_Vrc7_Apu* this )
23{
24 this->addr = 0;
25 this->next_time = 0;
26 this->osc.last_amp = 0;
27
28 OPLL_reset (&this->opll);
29 OPLL_setMask(&this->opll, this->mask);
30}
31
32void Vrc7_set_rate( struct Nes_Vrc7_Apu* this, int r )
33{
34 OPLL_set_quality( &this->opll, r < 44100 ? 0 : 1 );
35}
36
37void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int data )
38{
39 this->addr = data;
40}
41
42void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time );
43void Vrc7_write_data( struct Nes_Vrc7_Apu* this, blip_time_t time, int data )
44{
45 if ( time > this->next_time )
46 Vrc7_run_until( this, time );
47
48 OPLL_writeIO( &this->opll, 0, this->addr );
49 OPLL_writeIO( &this->opll, 1, data );
50}
51
52void Vrc7_end_frame( struct Nes_Vrc7_Apu* this, blip_time_t time )
53{
54 if ( time > this->next_time )
55 Vrc7_run_until( this, time );
56
57 this->next_time -= time;
58 assert( this->next_time >= 0 );
59
60 if ( this->osc.output )
61 Blip_set_modified( this->osc.output );
62}
63
64void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time )
65{
66 require( end_time > this->next_time );
67
68 blip_time_t time = this->next_time;
69 OPLL* opll = &this->opll; // cache
70 struct Blip_Buffer* const output = this-> osc.output;
71 if ( output )
72 {
73 do
74 {
75 int amp = OPLL_calc( opll ) << 1;
76 int delta = amp - this->osc.last_amp;
77 if ( delta )
78 {
79 this->osc.last_amp = amp;
80 Synth_offset_inline( &this->synth, time, delta, output );
81 }
82 time += period;
83 }
84 while ( time < end_time );
85 }
86
87 this->next_time = time;
88}