Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
chip-ahoyto
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
João Magalhães
chip-ahoyto
Commits
a4f0b4e9
Verified
Commit
a4f0b4e9
authored
2 years ago
by
João Magalhães
Browse files
Options
Downloads
Patches
Plain Diff
feat: initial support for beep
parent
9aa790de
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
examples/sdl/src/main.rs
+105
-10
105 additions, 10 deletions
examples/sdl/src/main.rs
resources/roms/pong_paul.ch8
+0
-0
0 additions, 0 deletions
resources/roms/pong_paul.ch8
with
105 additions
and
10 deletions
examples/sdl/src/main.rs
+
105
−
10
View file @
a4f0b4e9
use
chip_ahoyto
::
chip8
::{
Chip8
,
SCREEN_PIXEL_HEIGHT
,
SCREEN_PIXEL_WIDTH
};
use
sdl2
::{
event
::
Event
,
image
::
LoadSurface
,
keyboard
::
Keycode
,
pixels
::
PixelFormatEnum
,
surface
::
Surface
,
audio
::
AudioCallback
,
audio
::
AudioSpecDesired
,
event
::
Event
,
image
::
LoadSurface
,
keyboard
::
Keycode
,
pixels
::
PixelFormatEnum
,
surface
::
Surface
,
};
use
std
::{
fs
::
File
,
io
::
Read
};
use
std
::{
fs
::
File
,
io
::
Read
,
path
::
Path
};
const
COLORS
:
[[
u8
;
3
];
2
]
=
[[
255
,
255
,
255
],
[
80
,
203
,
147
]];
const
LOGIC_HZ
:
u32
=
24
0
;
const
LOGIC_HZ
:
u32
=
36
0
;
const
VISUAL_HZ
:
u32
=
60
;
const
IDLE_HZ
:
u32
=
60
;
const
BEEP_DURATION
:
f32
=
0.1
;
const
LOGIC_DELTA
:
u32
=
60
;
const
SCREEN_SCALE
:
f32
=
10.0
;
...
...
@@ -20,14 +23,58 @@ const TITLE: &str = "CHIP-Ahoyto";
// The title that is going to be presented initially to the user.
const
TITLE_INITIAL
:
&
str
=
"CHIP-Ahoyto [Drag and drop the ROM file to play]"
;
pub
struct
BeepCallback
{
phase_inc
:
f32
,
phase
:
f32
,
volume
:
f32
,
}
impl
AudioCallback
for
BeepCallback
{
type
Channel
=
f32
;
fn
callback
(
&
mut
self
,
out
:
&
mut
[
f32
])
{
for
x
in
out
.iter_mut
()
{
if
self
.phase
>=
0.0
&&
self
.phase
<=
0.5
{
*
x
=
self
.volume
;
}
else
{
*
x
=
-
self
.volume
;
}
self
.phase
=
(
self
.phase
+
self
.phase_inc
)
%
1.0
;
}
}
}
impl
BeepCallback
{
pub
fn
set_phase_inc
(
&
mut
self
,
phase_inc
:
f32
)
{
self
.phase_inc
=
phase_inc
;
}
pub
fn
set_phase
(
&
mut
self
,
phase
:
f32
)
{
self
.phase
=
phase
;
}
pub
fn
set_volume
(
&
mut
self
,
volume
:
f32
)
{
self
.volume
=
volume
;
}
}
pub
struct
State
{
system
:
Chip8
,
rom_loaded
:
bool
,
logic_frequency
:
u32
,
visual_frequency
:
u32
,
idle_frequency
:
u32
,
beep_duration
:
f32
,
next_tick_time
:
u32
,
beep_ticks
:
u32
,
pixel_color
:
[
u8
;
3
],
title
:
String
,
}
impl
State
{
pub
fn
set_title
(
&
mut
self
,
title
:
&
String
)
{
self
.title
=
title
.to_string
();
}
}
fn
main
()
{
...
...
@@ -39,21 +86,25 @@ fn main() {
logic_frequency
:
LOGIC_HZ
,
visual_frequency
:
VISUAL_HZ
,
idle_frequency
:
IDLE_HZ
,
beep_duration
:
BEEP_DURATION
,
next_tick_time
:
0
,
beep_ticks
:
0
,
pixel_color
:
COLORS
[
0
],
title
:
String
::
from
(
TITLE_INITIAL
),
};
// initializes the SDL sub-system
let
sdl
=
sdl2
::
init
()
.unwrap
();
let
video_subsystem
=
sdl
.video
()
.unwrap
();
let
mut
timer_subsystem
=
sdl
.timer
()
.unwrap
();
let
audio_subsystem
=
sdl
.audio
()
.unwrap
();
let
mut
event_pump
=
sdl
.event_pump
()
.unwrap
();
// creates the system window that is going to be used to
// show the emulator and sets it to the central are o screen
let
mut
window
=
video_subsystem
.window
(
TITLE
_INITIAL
,
TITLE
,
SCREEN_SCALE
as
u32
*
SCREEN_PIXEL_WIDTH
as
u32
,
SCREEN_SCALE
as
u32
*
SCREEN_PIXEL_HEIGHT
as
u32
,
)
...
...
@@ -90,6 +141,20 @@ fn main() {
canvas
.copy
(
&
background
,
None
,
None
)
.unwrap
();
canvas
.present
();
// creates a new audio device and prints the specs for it
let
desired_spec
=
AudioSpecDesired
{
freq
:
Some
(
44100
),
channels
:
Some
(
1
),
samples
:
None
,
};
let
device
=
audio_subsystem
.open_playback
(
None
,
&
desired_spec
,
|
spec
|
BeepCallback
{
phase_inc
:
440.0
/
spec
.freq
as
f32
,
phase
:
0.0
,
volume
:
0.5
,
})
.unwrap
();
'main
:
loop
{
while
let
Some
(
event
)
=
event_pump
.poll_event
()
{
match
event
{
...
...
@@ -104,7 +169,7 @@ fn main() {
keycode
:
Some
(
Keycode
::
Plus
),
..
}
=>
{
state
.logic_frequency
+
=
LOGIC_DELTA
;
state
.logic_frequency
=
state
.logic_frequency
.saturating_add
(
LOGIC_DELTA
)
;
None
}
...
...
@@ -112,22 +177,21 @@ fn main() {
keycode
:
Some
(
Keycode
::
Minus
),
..
}
=>
{
state
.logic_frequency
-
=
LOGIC_DELTA
;
state
.logic_frequency
=
state
.logic_frequency
.saturating_sub
(
LOGIC_DELTA
)
;
None
}
Event
::
DropFile
{
filename
,
..
}
=>
{
let
rom
=
read_file
(
&
filename
);
let
filebase
=
Path
::
new
(
&
filename
)
.file_name
()
.unwrap
()
.to_str
()
.unwrap
();
state
.system
.reset
();
state
.system
.load_rom
(
&
rom
);
state
.rom_loaded
=
true
;
canvas
.window_mut
()
.set_title
(
&
format!
(
"{} [Currently playing: {}]"
,
TITLE
,
filename
))
.unwrap
();
state
.set_title
(
&
format!
(
"{} [Currently playing: {}]"
,
TITLE
,
filebase
));
None
}
...
...
@@ -145,6 +209,16 @@ fn main() {
};
}
// updates the window tittle according to the specs of the machine
// and the provided base title
canvas
.window_mut
()
.set_title
(
&
format!
(
"{} [{} hz, {} fps]"
,
state
.title
,
state
.logic_frequency
,
state
.visual_frequency
))
.unwrap
();
// in case the ROM is not loaded we must delay next execution
// a little bit to avoid extreme CPU usage, at the same the
// background must be copied to allow resizing of window to
...
...
@@ -161,6 +235,10 @@ fn main() {
let
current_time
=
timer_subsystem
.ticks
();
if
current_time
>=
state
.next_tick_time
{
// allocates space for the variable that is going to control
// if a new beep was requested by the CHIP-8 logic cycles
let
mut
beep
=
false
;
// calculates the ratio between the logic and the visual frequency
// to make sure that the proper number of updates are performed
let
logic_visual_ratio
=
state
.logic_frequency
/
state
.visual_frequency
;
...
...
@@ -170,6 +248,23 @@ fn main() {
state
.system
.clock
();
state
.system
.clock_dt
();
state
.system
.clock_st
();
beep
|
=
state
.system
.beep
();
}
// in case a beep has been requested in the logical loop
// then the audio device is activated for the number of
// visual ticks associated with the beep duration (in seconds)
if
beep
{
device
.resume
();
state
.beep_ticks
=
(
state
.visual_frequency
as
f32
*
state
.beep_duration
)
as
u32
;
}
// decrements the number of pending beep ticks and checks
// if the value has reached zero in that case pauses the
// beep issuing device
state
.beep_ticks
=
state
.beep_ticks
.saturating_sub
(
1
);
if
state
.beep_ticks
==
0
{
device
.pause
();
}
// re-creates a vector of pixels from the system pixels
...
...
This diff is collapsed.
Click to expand it.
resources/roms/pong_paul.ch8
0 → 100644
+
0
−
0
View file @
a4f0b4e9
File added
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment