annotate src/console/Sap_Apu.cxx @ 2839:22a5075fc7f7

GPL Headers
author Paula Stanciu <paula.stanciu@gmail.com>
date Wed, 16 Jul 2008 20:57:17 +0300
parents 986f098da058
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
341
986f098da058 [svn] - merge in blargg's changes
nenolod
parents: 316
diff changeset
1 // Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
316
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
2
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
3 #include "Sap_Apu.h"
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
4
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
5 #include <string.h>
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
6
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
7 /* Copyright (C) 2006 Shay Green. This module is free software; you
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
8 can redistribute it and/or modify it under the terms of the GNU Lesser
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
9 General Public License as published by the Free Software Foundation; either
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
10 version 2.1 of the License, or (at your option) any later version. This
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
11 module is distributed in the hope that it will be useful, but WITHOUT ANY
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
13 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
14 details. You should have received a copy of the GNU Lesser General Public
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
15 License along with this module; if not, write to the Free Software Foundation,
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
17
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
18 #include "blargg_source.h"
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
19
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
20 int const max_frequency = 12000; // pure waves above this frequency are silenced
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
21
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
22 static void gen_poly( blargg_ulong mask, int count, byte* out )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
23 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
24 blargg_ulong n = 1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
25 do
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
26 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
27 int bits = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
28 int b = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
29 do
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
30 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
31 // implemented using "Galios configuration"
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
32 bits |= (n & 1) << b;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
33 n = (n >> 1) ^ (mask & -(n & 1));
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
34 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
35 while ( b++ < 7 );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
36 *out++ = bits;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
37 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
38 while ( --count );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
39 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
40
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
41 // poly5
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
42 int const poly5_len = (1 << 5) - 1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
43 blargg_ulong const poly5_mask = (1UL << poly5_len) - 1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
44 blargg_ulong const poly5 = 0x167C6EA1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
45
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
46 inline blargg_ulong run_poly5( blargg_ulong in, int shift )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
47 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
48 return (in << shift & poly5_mask) | (in >> (poly5_len - shift));
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
49 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
50
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
51 #define POLY_MASK( width, tap1, tap2 ) \
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
52 ((1UL << (width - 1 - tap1)) | (1UL << (width - 1 - tap2)))
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
53
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
54 Sap_Apu_Impl::Sap_Apu_Impl()
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
55 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
56 gen_poly( POLY_MASK( 4, 1, 0 ), sizeof poly4, poly4 );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
57 gen_poly( POLY_MASK( 9, 5, 0 ), sizeof poly9, poly9 );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
58 gen_poly( POLY_MASK( 17, 5, 0 ), sizeof poly17, poly17 );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
59
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
60 if ( 0 ) // comment out to recauculate poly5 constant
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
61 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
62 byte poly5 [4];
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
63 gen_poly( POLY_MASK( 5, 2, 0 ), sizeof poly5, poly5 );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
64 blargg_ulong n = poly5 [3] * 0x1000000L + poly5 [2] * 0x10000L +
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
65 poly5 [1] * 0x100L + poly5 [0];
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
66 blargg_ulong rev = n & 1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
67 for ( int i = 1; i < poly5_len; i++ )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
68 rev |= (n >> i & 1) << (poly5_len - i);
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
69 dprintf( "poly5: 0x%08lX\n", rev );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
70 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
71 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
72
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
73 Sap_Apu::Sap_Apu()
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
74 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
75 impl = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
76 for ( int i = 0; i < osc_count; i++ )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
77 osc_output( i, 0 );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
78 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
79
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
80 void Sap_Apu::reset( Sap_Apu_Impl* new_impl )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
81 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
82 impl = new_impl;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
83 last_time = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
84 poly5_pos = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
85 poly4_pos = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
86 polym_pos = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
87 control = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
88
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
89 for ( int i = 0; i < osc_count; i++ )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
90 memset( &oscs [i], 0, offsetof (osc_t,output) );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
91 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
92
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
93 inline void Sap_Apu::calc_periods()
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
94 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
95 // 15/64 kHz clock
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
96 int divider = 28;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
97 if ( this->control & 1 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
98 divider = 114;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
99
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
100 for ( int i = 0; i < osc_count; i++ )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
101 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
102 osc_t* const osc = &oscs [i];
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
103
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
104 int const osc_reload = osc->regs [0]; // cache
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
105 blargg_long period = (osc_reload + 1) * divider;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
106 static byte const fast_bits [osc_count] = { 1 << 6, 1 << 4, 1 << 5, 1 << 3 };
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
107 if ( this->control & fast_bits [i] )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
108 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
109 period = osc_reload + 4;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
110 if ( i & 1 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
111 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
112 period = osc_reload * 0x100L + osc [-1].regs [0] + 7;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
113 if ( !(this->control & fast_bits [i - 1]) )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
114 period = (period - 6) * divider;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
115
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
116 if ( (osc [-1].regs [1] & 0x1F) > 0x10 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
117 dprintf( "Use of slave channel in 16-bit mode not supported\n" );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
118 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
119 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
120 osc->period = period;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
121 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
122 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
123
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
124 void Sap_Apu::run_until( blip_time_t end_time )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
125 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
126 calc_periods();
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
127 Sap_Apu_Impl* const impl = this->impl; // cache
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
128
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
129 // 17/9-bit poly selection
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
130 byte const* polym = impl->poly17;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
131 int polym_len = poly17_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
132 if ( this->control & 0x80 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
133 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
134 polym_len = poly9_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
135 polym = impl->poly9;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
136 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
137 polym_pos %= polym_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
138
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
139 for ( int i = 0; i < osc_count; i++ )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
140 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
141 osc_t* const osc = &oscs [i];
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
142 blip_time_t time = last_time + osc->delay;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
143 blip_time_t const period = osc->period;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
144
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
145 // output
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
146 Blip_Buffer* output = osc->output;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
147 if ( output )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
148 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
149 output->set_modified();
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
150
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
151 int const osc_control = osc->regs [1]; // cache
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
152 int volume = (osc_control & 0x0F) * 2;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
153 if ( !volume || osc_control & 0x10 || // silent, DAC mode, or inaudible frequency
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
154 ((osc_control & 0xA0) == 0xA0 && period < 1789773 / 2 / max_frequency) )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
155 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
156 if ( !(osc_control & 0x10) )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
157 volume >>= 1; // inaudible frequency = half volume
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
158
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
159 int delta = volume - osc->last_amp;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
160 if ( delta )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
161 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
162 osc->last_amp = volume;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
163 impl->synth.offset( last_time, delta, output );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
164 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
165
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
166 // TODO: doesn't maintain high pass flip-flop (very minor issue)
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
167 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
168 else
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
169 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
170 // high pass
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
171 static byte const hipass_bits [osc_count] = { 1 << 2, 1 << 1, 0, 0 };
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
172 blip_time_t period2 = 0; // unused if no high pass
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
173 blip_time_t time2 = end_time;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
174 if ( this->control & hipass_bits [i] )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
175 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
176 period2 = osc [2].period;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
177 time2 = last_time + osc [2].delay;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
178 if ( osc->invert )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
179 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
180 // trick inner wave loop into inverting output
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
181 osc->last_amp -= volume;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
182 volume = -volume;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
183 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
184 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
185
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
186 if ( time < end_time || time2 < end_time )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
187 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
188 // poly source
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
189 static byte const poly1 [] = { 0x55, 0x55 }; // square wave
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
190 byte const* poly = poly1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
191 int poly_len = 8 * sizeof poly1; // can be just 2 bits, but this is faster
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
192 int poly_pos = osc->phase & 1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
193 int poly_inc = 1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
194 if ( !(osc_control & 0x20) )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
195 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
196 poly = polym;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
197 poly_len = polym_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
198 poly_pos = polym_pos;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
199 if ( osc_control & 0x40 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
200 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
201 poly = impl->poly4;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
202 poly_len = poly4_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
203 poly_pos = poly4_pos;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
204 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
205 poly_inc = period % poly_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
206 poly_pos = (poly_pos + osc->delay) % poly_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
207 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
208 poly_inc -= poly_len; // allows more optimized inner loop below
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
209
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
210 // square/poly5 wave
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
211 blargg_ulong wave = poly5;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
212 check( poly5 & 1 ); // low bit is set for pure wave
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
213 int poly5_inc = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
214 if ( !(osc_control & 0x80) )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
215 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
216 wave = run_poly5( wave, (osc->delay + poly5_pos) % poly5_len );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
217 poly5_inc = period % poly5_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
218 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
219
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
220 // Run wave and high pass interleved with each catching up to the other.
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
221 // Disabled high pass has no performance effect since inner wave loop
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
222 // makes no compromise for high pass, and only runs once in that case.
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
223 int osc_last_amp = osc->last_amp;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
224 do
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
225 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
226 // run high pass
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
227 if ( time2 < time )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
228 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
229 int delta = -osc_last_amp;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
230 if ( volume < 0 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
231 delta += volume;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
232 if ( delta )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
233 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
234 osc_last_amp += delta - volume;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
235 volume = -volume;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
236 impl->synth.offset( time2, delta, output );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
237 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
238 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
239 while ( time2 <= time ) // must advance *past* time to avoid hang
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
240 time2 += period2;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
241
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
242 // run wave
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
243 blip_time_t end = end_time;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
244 if ( end > time2 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
245 end = time2;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
246 while ( time < end )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
247 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
248 if ( wave & 1 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
249 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
250 int amp = volume & -(poly [poly_pos >> 3] >> (poly_pos & 7) & 1);
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
251 if ( (poly_pos += poly_inc) < 0 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
252 poly_pos += poly_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
253 int delta = amp - osc_last_amp;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
254 if ( delta )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
255 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
256 osc_last_amp = amp;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
257 impl->synth.offset( time, delta, output );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
258 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
259 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
260 wave = run_poly5( wave, poly5_inc );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
261 time += period;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
262 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
263 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
264 while ( time < end_time || time2 < end_time );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
265
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
266 osc->phase = poly_pos;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
267 osc->last_amp = osc_last_amp;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
268 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
269
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
270 osc->invert = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
271 if ( volume < 0 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
272 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
273 // undo inversion trickery
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
274 osc->last_amp -= volume;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
275 osc->invert = 1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
276 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
277 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
278 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
279
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
280 // maintain divider
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
281 blip_time_t remain = end_time - time;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
282 if ( remain > 0 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
283 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
284 blargg_long count = (remain + period - 1) / period;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
285 osc->phase ^= count;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
286 time += count * period;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
287 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
288 osc->delay = time - end_time;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
289 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
290
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
291 // advance polies
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
292 blip_time_t duration = end_time - last_time;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
293 last_time = end_time;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
294 poly4_pos = (poly4_pos + duration) % poly4_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
295 poly5_pos = (poly5_pos + duration) % poly5_len;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
296 polym_pos += duration; // will get %'d on next call
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
297 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
298
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
299 void Sap_Apu::write_data( blip_time_t time, unsigned addr, int data )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
300 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
301 run_until( time );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
302 int i = (addr ^ 0xD200) >> 1;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
303 if ( i < osc_count )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
304 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
305 oscs [i].regs [addr & 1] = data;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
306 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
307 else if ( addr == 0xD208 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
308 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
309 control = data;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
310 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
311 else if ( addr == 0xD209 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
312 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
313 oscs [0].delay = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
314 oscs [1].delay = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
315 oscs [2].delay = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
316 oscs [3].delay = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
317 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
318 /*
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
319 // TODO: are polynomials reset in this case?
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
320 else if ( addr == 0xD20F )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
321 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
322 if ( (data & 3) == 0 )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
323 polym_pos = 0;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
324 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
325 */
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
326 }
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
327
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
328 void Sap_Apu::end_frame( blip_time_t end_time )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
329 {
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
330 if ( end_time > last_time )
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
331 run_until( end_time );
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
332
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
333 last_time -= end_time;
fb513e10174e [svn] - merge libconsole-blargg into mainline libconsole:
nenolod
parents:
diff changeset
334 }