summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/nes_vrc7_apu.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/nes_vrc7_apu.c')
-rw-r--r--apps/codecs/libgme/nes_vrc7_apu.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/apps/codecs/libgme/nes_vrc7_apu.c b/apps/codecs/libgme/nes_vrc7_apu.c
new file mode 100644
index 0000000000..d8768bfc7e
--- /dev/null
+++ b/apps/codecs/libgme/nes_vrc7_apu.c
@@ -0,0 +1,89 @@
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, 1.0 );
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, double r )
33{
34 OPLL_set_quality( &this->opll, r < 44100 ? 0 : 1 );
35 OPLL_set_rate( &this->opll, (e_uint32)r );
36}
37
38void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int data )
39{
40 this->addr = data;
41}
42
43void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time );
44void Vrc7_write_data( struct Nes_Vrc7_Apu* this, blip_time_t time, int data )
45{
46 if ( time > this->next_time )
47 Vrc7_run_until( this, time );
48
49 OPLL_writeIO( &this->opll, 0, this->addr );
50 OPLL_writeIO( &this->opll, 1, data );
51}
52
53void Vrc7_end_frame( struct Nes_Vrc7_Apu* this, blip_time_t time )
54{
55 if ( time > this->next_time )
56 Vrc7_run_until( this, time );
57
58 this->next_time -= time;
59 assert( this->next_time >= 0 );
60
61 if ( this->osc.output )
62 Blip_set_modified( this->osc.output );
63}
64
65void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time )
66{
67 require( end_time > this->next_time );
68
69 blip_time_t time = this->next_time;
70 OPLL* opll = &this->opll; // cache
71 struct Blip_Buffer* const output = this-> osc.output;
72 if ( output )
73 {
74 do
75 {
76 int amp = OPLL_calc( opll ) << 1;
77 int delta = amp - this->osc.last_amp;
78 if ( delta )
79 {
80 this->osc.last_amp = amp;
81 Synth_offset_inline( &this->synth, time, delta, output );
82 }
83 time += period;
84 }
85 while ( time < end_time );
86 }
87
88 this->next_time = time;
89}