Class: Rubyboy::ApuChannels::Channel2

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyboy/apu_channels/channel2.rb

Constant Summary collapse

WAVE_DUTY =
[
  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], # 12.5%
  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0], # 25%
  [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0], # 50%
  [0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]  # 75%
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeChannel2

Returns a new instance of Channel2.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/rubyboy/apu_channels/channel2.rb', line 15

def initialize
  @cycles = 0
  @frequency = 0
  @frequency_timer = 0
  @wave_duty_position = 0

  @enabled = false
  @dac_enabled = false
  @length_enabled = false
  @is_upwards = false
  @is_decrementing = false
  @period = 0
  @period_timer = 0
  @current_volume = 0
  @initial_volume = 0
  @shadow_frequency = 0
  @length_timer = 0
  @wave_duty_pattern = 0
end

Instance Attribute Details

#enabledObject

Returns the value of attribute enabled.



6
7
8
# File 'lib/rubyboy/apu_channels/channel2.rb', line 6

def enabled
  @enabled
end

#wave_duty_positionObject

Returns the value of attribute wave_duty_position.



6
7
8
# File 'lib/rubyboy/apu_channels/channel2.rb', line 6

def wave_duty_position
  @wave_duty_position
end

Instance Method Details

#dac_outputObject



73
74
75
76
77
78
# File 'lib/rubyboy/apu_channels/channel2.rb', line 73

def dac_output
  return 0.0 unless @dac_enabled && @enabled

  ret = WAVE_DUTY[@wave_duty_pattern][@wave_duty_position] * @current_volume
  (ret / 7.5) - 1.0
end

#envelopeObject



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/rubyboy/apu_channels/channel2.rb', line 57

def envelope
  return if @period == 0

  @period_timer -= 1 if @period_timer > 0

  return if @period_timer != 0

  @period_timer = @period

  if @current_volume < 15 && @is_upwards
    @current_volume += 1
  elsif @current_volume > 0 && !@is_upwards
    @current_volume -= 1
  end
end

#lengthObject



50
51
52
53
54
55
# File 'lib/rubyboy/apu_channels/channel2.rb', line 50

def length
  return unless @length_enabled && @length_timer > 0

  @length_timer -= 1
  @enabled &= @length_timer > 0
end

#read_nr2x(x) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'lib/rubyboy/apu_channels/channel2.rb', line 80

def read_nr2x(x)
  case x
  when 1 then (@wave_duty_pattern << 6) | 0x3f
  when 2 then (@initial_volume << 4) | (@is_upwards ? 0x08 : 0x00) | @period
  when 3 then 0xff
  when 4 then (@length_enabled ? 0x40 : 0x00) | 0xbf
  else 0xff
  end
end

#step(cycles) ⇒ Object



35
36
37
38
39
40
41
42
43
# File 'lib/rubyboy/apu_channels/channel2.rb', line 35

def step(cycles)
  @cycles += cycles

  return if @cycles < @frequency_timer

  @cycles -= @frequency_timer
  @frequency_timer = (2048 - @frequency) * 4
  @wave_duty_position = (@wave_duty_position + 1) % 8
end

#step_fs(fs) ⇒ Object



45
46
47
48
# File 'lib/rubyboy/apu_channels/channel2.rb', line 45

def step_fs(fs)
  length if fs & 0x01 == 0
  envelope if fs == 7
end

#write_nr2x(x, val) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/rubyboy/apu_channels/channel2.rb', line 90

def write_nr2x(x, val)
  case x
  when 1
    @wave_duty_pattern = (val >> 6) & 0x03
    @length_timer = 64 - (val & 0x3f)
  when 2
    @is_upwards = (val & 0x08) > 0
    @initial_volume = (val >> 4)
    @period = val & 0x07
    @dac_enabled = val & 0xf8 > 0
    @enabled &= @dac_enabled
  when 3
    @frequency = (@frequency & 0x700) | val
  when 4
    @frequency = (@frequency & 0xff) | ((val & 0x07) << 8)
    @length_enabled = (val & 0x40) > 0
    @length_timer = 64 if @length_timer == 0
    return unless (val & 0x80) > 0 && @dac_enabled

    @enabled = true
    @period_timer = @period
    @current_volume = @initial_volume
  end
end