Skip to content

Commit 7de0a91

Browse files
committed
feat: add configurable sound controls with volume and frequency sliders
1 parent 4638069 commit 7de0a91

File tree

4 files changed

+94
-1
lines changed

4 files changed

+94
-1
lines changed

index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ <h1>CHIP-8 Emulator</h1>
5858
<input type="range" id="speed-slider" min="1" max="30" value="10">
5959
</label>
6060
</div>
61+
<div class="controls-group">
62+
<label>
63+
Volume: <span id="volume-value">10</span>%
64+
<input type="range" id="volume-slider" min="0" max="100" value="10">
65+
</label>
66+
</div>
67+
<div class="controls-group">
68+
<label>
69+
Frequency: <span id="frequency-value">440</span> Hz
70+
<input type="range" id="frequency-slider" min="200" max="800" value="440" step="10">
71+
</label>
72+
</div>
6173
</section>
6274

6375
<section class="main-grid">
@@ -133,6 +145,7 @@ <h3>Timers</h3>
133145
<script src="js/cpu.js"></script>
134146
<script src="js/renderer.js"></script>
135147
<script src="js/keyboard.js"></script>
148+
<script src="js/sound.js"></script>
136149
<script src="js/widgets/registers-widget.js"></script>
137150
<script src="js/widgets/memory-widget.js"></script>
138151
<script src="js/widgets/stack-widget.js"></script>

js/cpu.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ class CPU {
6969
}
7070

7171
playSound() {
72-
// Sound implementation handled externally
72+
if (this.soundTimer > 0 && this.sound) {
73+
this.sound.play();
74+
} else if (this.sound) {
75+
this.sound.stop();
76+
}
7377
}
7478

7579
executeInstruction(opcode) {

js/emulator.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ class Emulator {
33
this.cpu = new CPU();
44
this.renderer = new Renderer(10);
55
this.keyboard = new Keyboard();
6+
this.sound = new Sound();
67

78
this.cpu.renderer = this.renderer;
89
this.cpu.keyboard = this.keyboard;
10+
this.cpu.sound = this.sound;
911

1012
this.registersWidget = new RegistersWidget('registers-container');
1113
this.memoryWidget = new MemoryWidget('memory-container');
@@ -34,6 +36,21 @@ class Emulator {
3436
this.cpu.speed = parseInt(e.target.value);
3537
speedValue.textContent = e.target.value;
3638
});
39+
40+
const volumeSlider = document.getElementById('volume-slider');
41+
const volumeValue = document.getElementById('volume-value');
42+
volumeSlider.addEventListener('input', (e) => {
43+
const volume = parseInt(e.target.value) / 100;
44+
this.sound.setVolume(volume);
45+
volumeValue.textContent = e.target.value;
46+
});
47+
48+
const frequencySlider = document.getElementById('frequency-slider');
49+
const frequencyValue = document.getElementById('frequency-value');
50+
frequencySlider.addEventListener('input', (e) => {
51+
this.sound.setFrequency(parseInt(e.target.value));
52+
frequencyValue.textContent = e.target.value;
53+
});
3754
}
3855

3956
async loadROMFromSelect(event) {
@@ -129,9 +146,11 @@ class Emulator {
129146

130147
reset() {
131148
this.running = false;
149+
this.sound.stop();
132150
this.cpu = new CPU();
133151
this.cpu.renderer = this.renderer;
134152
this.cpu.keyboard = this.keyboard;
153+
this.cpu.sound = this.sound;
135154
this.renderer.clear();
136155
this.renderer.render();
137156
this.updateWidgets();

js/sound.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
class Sound {
2+
constructor() {
3+
this.audioContext = null;
4+
this.oscillator = null;
5+
this.gainNode = null;
6+
this.isPlaying = false;
7+
this.frequency = 440; // A4 note (440 Hz)
8+
this.volume = 0.1; // 10% volume
9+
}
10+
11+
init() {
12+
if (!this.audioContext) {
13+
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
14+
this.gainNode = this.audioContext.createGain();
15+
this.gainNode.connect(this.audioContext.destination);
16+
this.gainNode.gain.value = this.volume;
17+
}
18+
}
19+
20+
setVolume(volume) {
21+
this.volume = volume;
22+
if (this.gainNode) {
23+
this.gainNode.gain.value = volume;
24+
}
25+
}
26+
27+
setFrequency(frequency) {
28+
this.frequency = frequency;
29+
if (this.oscillator && this.isPlaying) {
30+
this.oscillator.frequency.setValueAtTime(frequency, this.audioContext.currentTime);
31+
}
32+
}
33+
34+
play() {
35+
if (this.isPlaying) return;
36+
37+
this.init();
38+
39+
this.oscillator = this.audioContext.createOscillator();
40+
this.oscillator.type = 'square'; // Square wave for classic beep sound
41+
this.oscillator.frequency.setValueAtTime(this.frequency, this.audioContext.currentTime);
42+
this.oscillator.connect(this.gainNode);
43+
this.oscillator.start();
44+
45+
this.isPlaying = true;
46+
}
47+
48+
stop() {
49+
if (!this.isPlaying || !this.oscillator) return;
50+
51+
this.oscillator.stop();
52+
this.oscillator.disconnect();
53+
this.oscillator = null;
54+
55+
this.isPlaying = false;
56+
}
57+
}

0 commit comments

Comments
 (0)