Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Libretro
retro8
Commits
d2da05b7
Commit
d2da05b7
authored
Dec 16, 2019
by
Jack
Browse files
working on APU sfx queue, moved Memory to its own file
parent
4ae08092
Changes
7
Hide whitespace changes
Inline
Side-by-side
projects/vs2017/retro8/retro8.vcxproj
View file @
d2da05b7
...
...
@@ -172,6 +172,7 @@
<ClCompile
Include=
"..\..\..\src\vm\gfx.cpp"
/>
<ClCompile
Include=
"..\..\..\src\vm\lua_bridge.cpp"
/>
<ClCompile
Include=
"..\..\..\src\vm\machine.cpp"
/>
<ClCompile
Include=
"..\..\..\src\vm\memory.cpp"
/>
<ClCompile
Include=
"..\..\..\src\vm\sound.cpp"
/>
</ItemGroup>
<ItemGroup>
...
...
@@ -213,6 +214,7 @@
<ClInclude
Include=
"..\..\..\src\vm\gfx.h"
/>
<ClInclude
Include=
"..\..\..\src\vm\lua_bridge.h"
/>
<ClInclude
Include=
"..\..\..\src\vm\machine.h"
/>
<ClInclude
Include=
"..\..\..\src\vm\memory.h"
/>
<ClInclude
Include=
"..\..\..\src\vm\sound.h"
/>
</ItemGroup>
<Import
Project=
"$(VCTargetsPath)\Microsoft.Cpp.targets"
/>
...
...
projects/vs2017/retro8/retro8.vcxproj.filters
View file @
d2da05b7
...
...
@@ -138,6 +138,9 @@
<ClInclude
Include=
"..\..\..\src\io\stegano.h"
>
<Filter>
src\io
</Filter>
</ClInclude>
<ClInclude
Include=
"..\..\..\src\vm\memory.h"
>
<Filter>
src\vm
</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile
Include=
"..\..\..\src\main.cpp"
>
...
...
@@ -272,5 +275,8 @@
<ClCompile
Include=
"..\..\..\src\io\stegano.cpp"
>
<Filter>
src\io
</Filter>
</ClCompile>
<ClCompile
Include=
"..\..\..\src\vm\memory.cpp"
>
<Filter>
src\vm
</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file
src/vm/machine.h
View file @
d2da05b7
...
...
@@ -5,6 +5,7 @@
#include "gfx.h"
#include "sound.h"
#include "lua_bridge.h"
#include "memory.h"
#include <SDL.h>
#include <array>
...
...
@@ -21,89 +22,6 @@ namespace retro8
bit_mask
<
button_t
>
previousButtons
;
};
namespace
address
{
static
constexpr
address_t
SPRITE_SHEET
=
0x0000
;
static
constexpr
address_t
SPRITE_FLAGS
=
0x3000
;
static
constexpr
address_t
CART_DATA
=
0x5e00
;
static
constexpr
address_t
PALETTES
=
0x5f00
;
static
constexpr
address_t
CLIP_RECT
=
0x5f20
;
static
constexpr
address_t
PEN_COLOR
=
0x5f25
;
static
constexpr
address_t
CURSOR
=
0x5f26
;
static
constexpr
address_t
CAMERA
=
0x5f28
;
static
constexpr
address_t
SCREEN_DATA
=
0x6000
;
static
constexpr
address_t
TILE_MAP_LOW
=
0x1000
;
static
constexpr
address_t
TILE_MAP_HIGH
=
0x2000
;
};
class
Memory
{
private:
uint8_t
memory
[
1024
*
32
];
static
constexpr
size_t
BYTES_PER_PALETTE
=
sizeof
(
retro8
::
gfx
::
palette_t
);
static
constexpr
size_t
BYTES_PER_SPRITE
=
sizeof
(
retro8
::
gfx
::
sprite_t
);
static
constexpr
size_t
ROWS_PER_TILE_MAP_HALF
=
32
;
public:
Memory
()
{
memset
(
memory
,
0
,
1024
*
32
);
paletteAt
(
gfx
::
DRAW_PALETTE_INDEX
)
->
reset
();
paletteAt
(
gfx
::
SCREEN_PALETTE_INDEX
)
->
reset
();
clipRect
()
->
reset
();
cursor
()
->
reset
();
}
uint8_t
*
base
()
{
return
memory
;
}
gfx
::
color_byte_t
*
penColor
()
{
return
as
<
gfx
::
color_byte_t
>
(
address
::
PEN_COLOR
);
}
gfx
::
cursor_t
*
cursor
()
{
return
as
<
gfx
::
cursor_t
>
(
address
::
CURSOR
);
}
gfx
::
camera_t
*
camera
()
{
return
as
<
gfx
::
camera_t
>
(
address
::
CAMERA
);
}
gfx
::
clip_rect_t
*
clipRect
()
{
return
as
<
gfx
::
clip_rect_t
>
(
address
::
CLIP_RECT
);
}
gfx
::
color_byte_t
*
spriteSheet
(
coord_t
x
,
coord_t
y
)
{
return
spriteSheet
()
+
x
/
gfx
::
PIXEL_TO_BYTE_RATIO
+
y
*
gfx
::
SPRITE_SHEET_PITCH
;
}
gfx
::
color_byte_t
*
spriteSheet
()
{
return
as
<
gfx
::
color_byte_t
>
(
address
::
SPRITE_SHEET
);
}
gfx
::
color_byte_t
*
screenData
()
{
return
as
<
gfx
::
color_byte_t
>
(
address
::
SCREEN_DATA
);
}
gfx
::
color_byte_t
*
screenData
(
coord_t
x
,
coord_t
y
)
{
return
screenData
()
+
y
*
gfx
::
SCREEN_PITCH
+
x
/
gfx
::
PIXEL_TO_BYTE_RATIO
;
}
integral_t
*
cartData
(
index_t
idx
)
{
return
as
<
integral_t
>
(
address
::
CART_DATA
+
idx
*
sizeof
(
integral_t
));
}
//TODO: ENDIANNESS!!
sprite_flags_t
*
spriteFlagsFor
(
sprite_index_t
index
)
{
return
as
<
sprite_flags_t
>
(
address
::
SPRITE_FLAGS
+
index
);
}
sprite_index_t
*
spriteInTileMap
(
coord_t
x
,
coord_t
y
)
{
static_assert
(
sizeof
(
sprite_index_t
)
==
1
,
"sprite_index_t must be 1 byte"
);
sprite_index_t
*
addr
;
if
(
y
>=
ROWS_PER_TILE_MAP_HALF
)
addr
=
as
<
sprite_index_t
>
(
address
::
TILE_MAP_LOW
)
+
x
+
(
y
-
ROWS_PER_TILE_MAP_HALF
)
*
gfx
::
TILE_MAP_WIDTH
*
sizeof
(
sprite_index_t
);
else
addr
=
as
<
sprite_index_t
>
(
address
::
TILE_MAP_HIGH
)
+
x
+
y
*
gfx
::
TILE_MAP_WIDTH
*
sizeof
(
sprite_index_t
);
assert
((
addr
>=
memory
+
address
::
TILE_MAP_LOW
&&
addr
<=
memory
+
address
::
TILE_MAP_LOW
*
gfx
::
TILE_MAP_WIDTH
*
gfx
::
TILE_MAP_HEIGHT
*
sizeof
(
sprite_index_t
)));
return
addr
;
}
gfx
::
sprite_t
*
spriteAt
(
sprite_index_t
index
)
{
return
reinterpret_cast
<
gfx
::
sprite_t
*>
(
&
memory
[
address
::
SPRITE_SHEET
+
(
index
%
gfx
::
SPRITES_PER_SPRITE_SHEET_ROW
)
*
gfx
::
SPRITE_BYTES_PER_SPRITE_ROW
]
+
(
index
/
gfx
::
SPRITES_PER_SPRITE_SHEET_ROW
)
*
gfx
::
SPRITE_SHEET_PITCH
*
gfx
::
SPRITE_HEIGHT
);
}
gfx
::
palette_t
*
paletteAt
(
palette_index_t
index
)
{
return
reinterpret_cast
<
gfx
::
palette_t
*>
(
&
memory
[
address
::
PALETTES
+
index
*
BYTES_PER_PALETTE
]);
}
template
<
typename
T
>
T
*
as
(
address_t
addr
)
{
return
reinterpret_cast
<
T
*>
(
&
memory
[
addr
]);
}
};
class
Machine
{
private:
...
...
@@ -122,7 +40,7 @@ namespace retro8
public:
Machine
()
Machine
()
:
_sound
(
_memory
)
{
}
...
...
src/vm/memory.cpp
0 → 100644
View file @
d2da05b7
#include "memory.h"
\ No newline at end of file
src/vm/memory.h
0 → 100644
View file @
d2da05b7
#pragma once
#include "common.h"
#include "defines.h"
#include "gfx.h"
#include "sound.h"
#include "lua_bridge.h"
#include <SDL.h>
#include <array>
#include <random>
namespace
retro8
{
namespace
address
{
static
constexpr
address_t
SPRITE_SHEET
=
0x0000
;
static
constexpr
address_t
SPRITE_FLAGS
=
0x3000
;
static
constexpr
address_t
CART_DATA
=
0x5e00
;
static
constexpr
address_t
PALETTES
=
0x5f00
;
static
constexpr
address_t
CLIP_RECT
=
0x5f20
;
static
constexpr
address_t
PEN_COLOR
=
0x5f25
;
static
constexpr
address_t
CURSOR
=
0x5f26
;
static
constexpr
address_t
CAMERA
=
0x5f28
;
static
constexpr
address_t
SCREEN_DATA
=
0x6000
;
static
constexpr
address_t
TILE_MAP_LOW
=
0x1000
;
static
constexpr
address_t
TILE_MAP_HIGH
=
0x2000
;
};
class
Memory
{
private:
uint8_t
memory
[
1024
*
32
];
static
constexpr
size_t
BYTES_PER_PALETTE
=
sizeof
(
retro8
::
gfx
::
palette_t
);
static
constexpr
size_t
BYTES_PER_SPRITE
=
sizeof
(
retro8
::
gfx
::
sprite_t
);
static
constexpr
size_t
ROWS_PER_TILE_MAP_HALF
=
32
;
public:
Memory
()
{
memset
(
memory
,
0
,
1024
*
32
);
paletteAt
(
gfx
::
DRAW_PALETTE_INDEX
)
->
reset
();
paletteAt
(
gfx
::
SCREEN_PALETTE_INDEX
)
->
reset
();
clipRect
()
->
reset
();
cursor
()
->
reset
();
}
uint8_t
*
base
()
{
return
memory
;
}
gfx
::
color_byte_t
*
penColor
()
{
return
as
<
gfx
::
color_byte_t
>
(
address
::
PEN_COLOR
);
}
gfx
::
cursor_t
*
cursor
()
{
return
as
<
gfx
::
cursor_t
>
(
address
::
CURSOR
);
}
gfx
::
camera_t
*
camera
()
{
return
as
<
gfx
::
camera_t
>
(
address
::
CAMERA
);
}
gfx
::
clip_rect_t
*
clipRect
()
{
return
as
<
gfx
::
clip_rect_t
>
(
address
::
CLIP_RECT
);
}
gfx
::
color_byte_t
*
spriteSheet
(
coord_t
x
,
coord_t
y
)
{
return
spriteSheet
()
+
x
/
gfx
::
PIXEL_TO_BYTE_RATIO
+
y
*
gfx
::
SPRITE_SHEET_PITCH
;
}
gfx
::
color_byte_t
*
spriteSheet
()
{
return
as
<
gfx
::
color_byte_t
>
(
address
::
SPRITE_SHEET
);
}
gfx
::
color_byte_t
*
screenData
()
{
return
as
<
gfx
::
color_byte_t
>
(
address
::
SCREEN_DATA
);
}
gfx
::
color_byte_t
*
screenData
(
coord_t
x
,
coord_t
y
)
{
return
screenData
()
+
y
*
gfx
::
SCREEN_PITCH
+
x
/
gfx
::
PIXEL_TO_BYTE_RATIO
;
}
integral_t
*
cartData
(
index_t
idx
)
{
return
as
<
integral_t
>
(
address
::
CART_DATA
+
idx
*
sizeof
(
integral_t
));
}
//TODO: ENDIANNESS!!
sprite_flags_t
*
spriteFlagsFor
(
sprite_index_t
index
)
{
return
as
<
sprite_flags_t
>
(
address
::
SPRITE_FLAGS
+
index
);
}
sprite_index_t
*
spriteInTileMap
(
coord_t
x
,
coord_t
y
)
{
static_assert
(
sizeof
(
sprite_index_t
)
==
1
,
"sprite_index_t must be 1 byte"
);
sprite_index_t
*
addr
;
if
(
y
>=
ROWS_PER_TILE_MAP_HALF
)
addr
=
as
<
sprite_index_t
>
(
address
::
TILE_MAP_LOW
)
+
x
+
(
y
-
ROWS_PER_TILE_MAP_HALF
)
*
gfx
::
TILE_MAP_WIDTH
*
sizeof
(
sprite_index_t
);
else
addr
=
as
<
sprite_index_t
>
(
address
::
TILE_MAP_HIGH
)
+
x
+
y
*
gfx
::
TILE_MAP_WIDTH
*
sizeof
(
sprite_index_t
);
assert
((
addr
>=
memory
+
address
::
TILE_MAP_LOW
&&
addr
<=
memory
+
address
::
TILE_MAP_LOW
*
gfx
::
TILE_MAP_WIDTH
*
gfx
::
TILE_MAP_HEIGHT
*
sizeof
(
sprite_index_t
)));
return
addr
;
}
gfx
::
sprite_t
*
spriteAt
(
sprite_index_t
index
)
{
return
reinterpret_cast
<
gfx
::
sprite_t
*>
(
&
memory
[
address
::
SPRITE_SHEET
+
(
index
%
gfx
::
SPRITES_PER_SPRITE_SHEET_ROW
)
*
gfx
::
SPRITE_BYTES_PER_SPRITE_ROW
]
+
(
index
/
gfx
::
SPRITES_PER_SPRITE_SHEET_ROW
)
*
gfx
::
SPRITE_SHEET_PITCH
*
gfx
::
SPRITE_HEIGHT
);
}
gfx
::
palette_t
*
paletteAt
(
palette_index_t
index
)
{
return
reinterpret_cast
<
gfx
::
palette_t
*>
(
&
memory
[
address
::
PALETTES
+
index
*
BYTES_PER_PALETTE
]);
}
template
<
typename
T
>
T
*
as
(
address_t
addr
)
{
return
reinterpret_cast
<
T
*>
(
&
memory
[
addr
]);
}
};
}
\ No newline at end of file
src/vm/sound.cpp
View file @
d2da05b7
#include "sound.h"
#include <random>
#include <cassert>
using
namespace
retro8
;
using
namespace
retro8
::
sfx
;
...
...
@@ -255,28 +256,92 @@ void APU::close()
SDL_CloseAudioDevice
(
device
);
}
void
APU
::
play
(
sound_index_t
index
,
channel_index_t
channel
,
uint32_t
start
,
uint32_t
end
)
{
queueMutex
.
lock
();
queue
.
push_back
({
index
,
channel
,
start
,
end
});
queueMutex
.
unlock
();
}
void
APU
::
handleCommands
()
{
if
(
queueMutex
.
try_lock
())
{
for
(
Command
&
c
:
queue
)
{
/* stop sound on channel*/
if
(
c
.
index
==
-
1
)
{
assert
(
c
.
channel
>=
0
&&
c
.
channel
<=
channels
.
size
());
channels
[
c
.
channel
].
sound
=
nullptr
;
continue
;
}
/* stop sound from looping */
else
if
(
c
.
index
==
-
2
)
{
continue
;
}
/* stop sound on all channels that are playing it*/
else
if
(
c
.
channel
==
-
2
)
{
for
(
auto
&
chan
:
channels
)
if
(
chan
.
soundIndex
==
c
.
index
)
chan
.
sound
=
nullptr
;
continue
;
}
/* find first available channel*/
else
if
(
c
.
channel
==
-
1
)
for
(
size_t
i
=
0
;
channels
.
size
();
++
i
)
if
(
!
channels
[
i
].
sound
)
c
.
channel
=
i
;
if
(
c
.
channel
>=
0
&&
c
.
channel
<
channels
.
size
()
&&
c
.
index
>=
0
&&
c
.
index
<=
SOUND_COUNT
)
{
auto
&
channel
=
channels
[
c
.
channel
];
//channel.sound =
}
}
queue
.
clear
();
}
void
APU
::
renderSounds
(
int16_t
*
dest
,
size_t
samples
)
/* stop sound on channel*/
}
void
APU
::
renderSounds
(
int16_t
*
dest
,
size_t
totalSamples
)
{
constexpr
size_t
rate
=
44100
;
size_t
samplePerTick
=
(
44100
/
128
)
*
(
sstate
.
sound
->
speed
+
1
);
int16_t
maxVolume
=
4096
;
while
(
samples
>
0
)
for
(
SoundState
state
:
channels
)
{
/* generate the maximum amount of samples available for same note */
// TODO: optimize if next note is equal to current
size_t
available
=
std
::
min
(
samples
,
samplePerTick
-
(
sstate
.
position
%
samplePerTick
));
const
SoundSample
&
sample
=
sstate
.
sound
->
samples
[
sstate
.
sample
];
/* render samples */
dsp
.
squareWave
(
Note
::
frequency
(
sample
.
pitch
()),
(
4096
/
8
)
*
sample
.
volume
(),
0
,
sstate
.
position
,
dest
,
samples
);
samples
-=
available
;
dest
+=
available
;
sstate
.
position
+=
available
;
sstate
.
sample
=
sstate
.
position
/
samplePerTick
;
}
if
(
state
.
sound
)
{
int16_t
*
buffer
=
dest
;
size_t
samples
=
totalSamples
;
while
(
samples
>
0
&&
state
.
sound
)
{
/* generate the maximum amount of samples available for same note */
// TODO: optimize if next note is equal to current
size_t
available
=
std
::
min
(
samples
,
samplePerTick
-
(
sstate
.
position
%
samplePerTick
));
const
SoundSample
&
sample
=
sstate
.
sound
->
samples
[
sstate
.
sample
];
/* render samples */
dsp
.
squareWave
(
Note
::
frequency
(
sample
.
pitch
()),
(
maxVolume
/
8
)
*
sample
.
volume
(),
0
,
sstate
.
position
,
dest
,
samples
);
samples
-=
available
;
dest
+=
available
;
sstate
.
position
+=
available
;
sstate
.
sample
=
sstate
.
position
/
samplePerTick
;
if
(
sstate
.
sample
>=
sstate
.
end
)
sstate
.
sound
=
nullptr
;
}
}
}
}
\ No newline at end of file
src/vm/sound.h
View file @
d2da05b7
...
...
@@ -4,17 +4,23 @@
#include "common.h"
#include <array>
#include <vector>
#include <mutex>
#include <SDL_audio.h>
#if SOUND_ENABLED
namespace
retro8
{
class
Memory
;
namespace
sfx
{
using
volume_t
=
int32_t
;
using
pitch_t
=
int32_t
;
using
frequency_t
=
int32_t
;
using
channel_index_t
=
int32_t
;
using
sound_index_t
=
int32_t
;
enum
class
Waveform
{
...
...
@@ -85,12 +91,15 @@ namespace retro8
static
constexpr
size_t
SOUND_COUNT
=
64
;
static
constexpr
size_t
MUSIC_COUNT
=
64
;
static
constexpr
size_t
TICKS_PER_SECOND
=
128
;
struct
SoundState
{
const
Sound
*
sound
;
uint32_t
soundIndex
;
uint32_t
sample
;
uint32_t
position
;
// absolute
uint32_t
end
;
};
class
DSP
...
...
@@ -116,16 +125,38 @@ namespace retro8
class
APU
{
retro8
::
Memory
&
memory
;
struct
Command
{
sound_index_t
index
;
channel_index_t
channel
;
uint32_t
start
;
uint32_t
end
;
};
static
constexpr
size_t
CHANNEL_COUNT
=
4
;
SDL_AudioSpec
spec
;
SDL_AudioDeviceID
device
;
std
::
array
<
SoundState
,
CHANNEL_COUNT
>
channels
;
std
::
mutex
queueMutex
;
std
::
vector
<
Command
>
queue
;
void
handleCommands
();
public:
APU
(
Memory
&
memory
)
:
memory
(
memory
)
{
}
void
init
();
void
close
();
void
resume
();
void
pause
();
void
play
(
sound_index_t
index
,
channel_index_t
channel
,
uint32_t
start
,
uint32_t
end
);
void
renderSounds
(
int16_t
*
dest
,
size_t
samples
);
};
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment