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
a7b14f3a
Commit
a7b14f3a
authored
Dec 17, 2019
by
Jack
Browse files
some additional, not yet working, code about music rendering
parent
74d11cd1
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/views/game_view.cpp
View file @
a7b14f3a
...
...
@@ -108,7 +108,7 @@ void GameView::render()
retro8
::
io
::
Loader
loader
;
if
(
_path
.
empty
())
_path
=
"
get-out
.png"
;
_path
=
"
mario
.png"
;
loader
.
load
(
_path
,
machine
);
...
...
src/vm/lua_bridge.cpp
View file @
a7b14f3a
...
...
@@ -606,7 +606,12 @@ namespace sound
{
int
music
(
lua_State
*
L
)
{
//TODO: implement
sfx
::
music_index_t
index
=
lua_tonumber
(
L
,
1
);
int32_t
fadeMs
=
lua_to_or_default
(
L
,
number
,
2
,
1
);
int32_t
mask
=
lua_to_or_default
(
L
,
number
,
3
,
0
);
machine
.
sound
().
music
(
index
,
fadeMs
,
mask
);
return
0
;
}
...
...
src/vm/sound.cpp
View file @
a7b14f3a
...
...
@@ -232,7 +232,14 @@ void APU::close()
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
});
queue
.
emplace_back
(
index
,
channel
,
start
,
end
);
queueMutex
.
unlock
();
}
void
APU
::
music
(
music_index_t
index
,
int32_t
fadeMs
,
int32_t
mask
)
{
queueMutex
.
lock
();
queue
.
emplace_back
(
index
,
fadeMs
,
mask
);
queueMutex
.
unlock
();
}
...
...
@@ -242,49 +249,80 @@ void APU::handleCommands()
{
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
)
if
(
!
c
.
isMusic
)
{
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
;
i
<
channels
.
size
();
++
i
)
if
(
!
channels
[
i
].
sound
)
{
c
.
channel
=
i
;
break
;
}
auto
&
s
=
c
.
sound
;
/* stop sound on channel*/
if
(
s
.
index
==
-
1
)
{
assert
(
s
.
channel
>=
0
&&
s
.
channel
<=
channels
.
size
());
channels
[
s
.
channel
].
sound
=
nullptr
;
continue
;
}
/* stop sound from looping */
else
if
(
s
.
index
==
-
2
)
{
continue
;
}
/* stop sound on all channels that are playing it*/
else
if
(
s
.
channel
==
-
2
)
{
for
(
auto
&
chan
:
channels
)
if
(
chan
.
soundIndex
==
s
.
index
)
chan
.
sound
=
nullptr
;
continue
;
}
/* find first available channel*/
else
if
(
s
.
channel
==
-
1
)
for
(
size_t
i
=
0
;
i
<
channels
.
size
();
++
i
)
if
(
!
channels
[
i
].
sound
)
{
s
.
channel
=
i
;
break
;
}
if
(
c
.
channel
>=
0
&&
c
.
channel
<
channels
.
size
()
&&
c
.
index
>=
0
&&
c
.
index
<=
SOUND_COUNT
)
{
/* overtaking channel */
auto
&
channel
=
channels
[
c
.
channel
];
if
(
s
.
channel
>=
0
&&
s
.
channel
<
channels
.
size
()
&&
s
.
index
>=
0
&&
s
.
index
<=
SOUND_COUNT
)
{
/* overtaking channel */
auto
&
channel
=
channels
[
s
.
channel
];
channel
.
soundIndex
=
c
.
index
;
channel
.
sound
=
memory
.
sound
(
c
.
index
);
channel
.
end
=
c
.
end
;
channel
.
sample
=
c
.
start
;
channel
.
soundIndex
=
s
.
index
;
channel
.
sound
=
memory
.
sound
(
s
.
index
);
channel
.
end
=
s
.
end
;
channel
.
sample
=
s
.
start
;
size_t
samplePerTick
=
(
44100
/
128
)
*
(
channel
.
sound
->
speed
+
1
);
size_t
samplePerTick
=
(
44100
/
128
)
*
(
channel
.
sound
->
speed
+
1
);
channel
.
position
=
c
.
start
*
samplePerTick
;
channel
.
position
=
s
.
start
*
samplePerTick
;
}
}
else
{
const
auto
&
m
=
c
.
music
;
if
(
m
.
index
==
-
1
)
mstate
.
music
=
nullptr
;
else
{
mstate
.
pattern
=
m
.
index
;
mstate
.
music
=
memory
.
music
(
m
.
index
);
mstate
.
channelMask
=
m
.
mask
;
for
(
size_t
i
=
0
;
i
<
CHANNEL_COUNT
;
++
i
)
{
if
(
mstate
.
music
->
isChannelEnabled
(
i
))
{
mstate
.
channels
[
i
].
sound
=
memory
.
sound
(
mstate
.
music
->
sound
(
i
));
mstate
.
channels
[
i
].
sample
=
0
;
mstate
.
channels
[
i
].
position
=
0
;
mstate
.
channels
[
i
].
end
=
31
;
//TODO: fix according to behavior
}
else
mstate
.
channels
[
i
].
sound
=
nullptr
;
}
}
}
}
...
...
@@ -297,12 +335,12 @@ void APU::handleCommands()
void
APU
::
updateMusic
()
{
if
(
m
usic
.
music
)
if
(
m
state
.
music
)
{
for
(
channel_index_t
i
=
0
;
i
<
CHANNEL_COUNT
;
++
i
)
{
/* will use channel if channel is forced or there's no sound currently playing there */
bool
willUseChannel
=
((
m
usic
.
channelMask
&
(
1
<<
i
))
!=
0
)
||
!
channels
[
i
].
sound
;
bool
willUseChannel
=
((
m
state
.
channelMask
&
(
1
<<
i
))
!=
0
)
||
!
channels
[
i
].
sound
;
}
...
...
@@ -311,6 +349,83 @@ void APU::updateMusic()
}
void
APU
::
updateChannel
(
SoundState
&
channel
,
const
Music
*
music
)
{
if
(
!
music
)
{
if
(
channel
.
sample
>=
channel
.
end
)
channel
.
sound
=
nullptr
;
}
else
{
/* sound is ended, behavior depends on flag for music*/
if
(
channel
.
sample
>=
channel
.
end
)
{
if
(
music
->
isStop
())
this
->
mstate
.
music
=
nullptr
;
else
if
(
music
->
isLoopEnd
()
||
this
->
mstate
.
pattern
==
MUSIC_COUNT
-
1
)
{
music_index_t
i
=
this
->
mstate
.
pattern
-
1
;
const
Music
*
next
=
nullptr
;
while
(
i
>=
0
)
{
next
=
memory
.
music
(
i
);
if
(
next
->
isLoopBegin
()
||
i
==
0
)
break
;
--
i
;
}
this
->
mstate
.
pattern
=
i
;
this
->
mstate
.
music
=
next
;
}
}
else
{
channel
.
sound
=
nullptr
;
++
this
->
mstate
.
pattern
;
this
->
mstate
.
music
=
memory
.
music
(
this
->
mstate
.
pattern
);
}
}
}
void
APU
::
renderSound
(
const
SoundState
&
channel
,
int16_t
*
buffer
,
size_t
samples
)
{
const
SoundSample
&
sample
=
channel
.
sound
->
samples
[
channel
.
sample
];
constexpr
int16_t
maxVolume
=
4096
;
const
int16_t
volume
=
(
maxVolume
/
8
)
*
sample
.
volume
();
const
frequency_t
frequency
=
Note
::
frequency
(
sample
.
pitch
());
/* render samples */
switch
(
sample
.
waveform
())
{
case
Waveform
::
SQUARE
:
dsp
.
squareWave
(
frequency
,
volume
,
0
,
channel
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
TILTED_SAW
:
dsp
.
tiltedSawtoothWave
(
frequency
,
volume
,
0
,
0.85
f
,
channel
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
SAW
:
dsp
.
sawtoothWave
(
frequency
,
volume
,
0
,
channel
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
TRIANGLE
:
dsp
.
triangleWave
(
frequency
,
volume
,
0
,
channel
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
PULSE
:
dsp
.
pulseWave
(
frequency
,
volume
,
0
,
1
/
3.0
f
,
channel
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
ORGAN
:
dsp
.
organWave
(
frequency
,
volume
,
0
,
0.5
f
,
channel
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
NOISE
:
dsp
.
noise
(
frequency
,
volume
,
channel
.
position
,
buffer
,
samples
);
break
;
}
}
void
APU
::
renderSounds
(
int16_t
*
dest
,
size_t
totalSamples
)
{
handleCommands
();
...
...
@@ -320,60 +435,30 @@ void APU::renderSounds(int16_t* dest, size_t totalSamples)
memset
(
dest
,
0
,
sizeof
(
int16_t
)
*
totalSamples
);
for
(
SoundState
&
state
:
channels
)
for
(
size_t
i
=
0
;
i
<
CHANNEL_COUNT
;
++
i
)
{
if
(
state
.
sound
)
{
int16_t
*
buffer
=
dest
;
size_t
samples
=
totalSamples
;
size_t
samplePerTick
=
(
44100
/
128
)
*
(
state
.
sound
->
speed
+
1
);
int16_t
*
buffer
=
dest
;
size_t
samples
=
totalSamples
;
while
(
samples
>
0
&&
state
.
sound
)
SoundState
&
channel
=
channels
[
i
].
sound
?
channels
[
i
]
:
mstate
.
channels
[
i
];
const
Music
*
music
=
&
channel
==
&
this
->
mstate
.
channels
[
i
]
?
this
->
mstate
.
music
:
nullptr
;
//TODO: crappy comparison
if
(
channel
.
sound
)
{
const
size_t
samplePerTick
=
(
44100
/
128
)
*
(
channel
.
sound
->
speed
+
1
);
while
(
samples
>
0
&&
channel
.
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
-
(
state
.
position
%
samplePerTick
));
const
SoundSample
&
sample
=
state
.
sound
->
samples
[
state
.
sample
];
const
int16_t
volume
=
(
maxVolume
/
8
)
*
sample
.
volume
();
const
frequency_t
frequency
=
Note
::
frequency
(
sample
.
pitch
());
/* render samples */
switch
(
sample
.
waveform
())
{
case
Waveform
::
SQUARE
:
dsp
.
squareWave
(
frequency
,
volume
,
0
,
state
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
TILTED_SAW
:
dsp
.
tiltedSawtoothWave
(
frequency
,
volume
,
0
,
0.85
f
,
state
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
SAW
:
dsp
.
sawtoothWave
(
frequency
,
volume
,
0
,
state
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
TRIANGLE
:
dsp
.
triangleWave
(
frequency
,
volume
,
0
,
state
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
PULSE
:
dsp
.
pulseWave
(
frequency
,
volume
,
0
,
1
/
3.0
f
,
state
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
ORGAN
:
dsp
.
organWave
(
frequency
,
volume
,
0
,
0.5
f
,
state
.
position
,
buffer
,
samples
);
break
;
case
Waveform
::
NOISE
:
dsp
.
noise
(
frequency
,
volume
,
state
.
position
,
buffer
,
samples
);
break
;
}
size_t
available
=
std
::
min
(
samples
,
samplePerTick
-
(
channel
.
position
%
samplePerTick
));
renderSound
(
channel
,
buffer
,
available
);
samples
-=
available
;
buffer
+=
available
;
state
.
position
+=
available
;
state
.
sample
=
state
.
position
/
samplePerTick
;
channel
.
position
+=
available
;
channel
.
sample
=
channel
.
position
/
samplePerTick
;
if
(
state
.
sample
>=
state
.
end
)
state
.
sound
=
nullptr
;
updateChannel
(
channel
,
music
);
}
}
}
...
...
src/vm/sound.h
View file @
a7b14f3a
...
...
@@ -103,7 +103,7 @@ namespace retro8
inline
bool
isLoopEnd
()
const
{
return
(
indices
[
1
]
&
LOOP_FLAG
)
!=
0
;
}
inline
bool
isStop
()
const
{
return
(
indices
[
2
]
&
LOOP_FLAG
)
!=
0
;
}
inline
bool
isChannelEnabled
(
channel_index_t
channel
)
{
return
(
indices
[
channel
]
&
SOUND_ON_FLAG
)
!=
0
;
}
inline
bool
isChannelEnabled
(
channel_index_t
channel
)
const
{
return
(
indices
[
channel
]
&
SOUND_ON_FLAG
)
!=
0
;
}
sound_index_t
sound
(
channel_index_t
channel
)
const
{
return
indices
[
channel
]
&
SOUND_INDEX_MASK
;
}
};
...
...
@@ -126,7 +126,7 @@ namespace retro8
struct
MusicState
{
std
::
array
<
SoundState
,
4
>
channels
;
Music
*
music
;
const
Music
*
music
;
music_index_t
pattern
;
uint8_t
channelMask
;
};
...
...
@@ -162,10 +162,28 @@ namespace retro8
struct
Command
{
sound_index_t
index
;
channel_index_t
channel
;
uint32_t
start
;
uint32_t
end
;
bool
isMusic
;
union
{
struct
{
sound_index_t
index
;
channel_index_t
channel
;
uint32_t
start
;
uint32_t
end
;
}
sound
;
struct
{
music_index_t
index
;
int32_t
fadeMs
;
int32_t
mask
;
}
music
;
};
Command
(
sound_index_t
index
,
channel_index_t
channel
,
uint32_t
start
,
uint32_t
end
)
:
isMusic
(
false
),
sound
({
index
,
channel
,
start
,
end
})
{
}
Command
(
music_index_t
index
,
int32_t
fadeMs
,
int32_t
mask
)
:
isMusic
(
true
),
music
({
index
,
fadeMs
,
mask
})
{
}
};
...
...
@@ -174,7 +192,7 @@ namespace retro8
std
::
array
<
SoundState
,
CHANNEL_COUNT
>
channels
;
MusicState
m
usic
;
MusicState
m
state
;
std
::
mutex
queueMutex
;
std
::
vector
<
Command
>
queue
;
...
...
@@ -182,6 +200,8 @@ namespace retro8
void
handleCommands
();
void
updateMusic
();
void
renderSound
(
const
SoundState
&
sound
,
int16_t
*
buffer
,
size_t
samples
);
void
updateChannel
(
SoundState
&
channel
,
const
Music
*
music
);
public:
APU
(
Memory
&
memory
)
:
memory
(
memory
)
{
}
...
...
@@ -193,6 +213,7 @@ namespace retro8
void
pause
();
void
play
(
sound_index_t
index
,
channel_index_t
channel
,
uint32_t
start
,
uint32_t
end
);
void
music
(
music_index_t
index
,
int32_t
fadeMs
,
int32_t
mask
);
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