Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
PoroCYon
oidos
Commits
8516feba
Commit
8516feba
authored
Apr 03, 2017
by
Aske Simon Christensen
Browse files
Generate multiple notes per tone into the cache
parent
702c7c5d
Changes
2
Hide whitespace changes
Inline
Side-by-side
synth/src/cache.rs
View file @
8516feba
use
std
::
ops
::
Index
;
use
std
::
ops
::
{
Index
,
IndexMut
}
;
use
generate
::{
Sample
,
SoundGenerator
};
const
BLOCK_SHIFT
:
usize
=
1
6
;
const
BLOCK_SHIFT
:
usize
=
1
2
;
const
BLOCK_SIZE
:
usize
=
1
<<
BLOCK_SHIFT
;
const
BLOCK_MASK
:
usize
=
BLOCK_SIZE
-
1
;
struct
BlockVec
<
T
>
{
size
:
usize
,
v
:
Vec
<
Vec
<
T
>>
}
...
...
@@ -21,76 +20,85 @@ impl<T> Index<usize> for BlockVec<T> {
}
}
impl
<
T
:
Default
+
Clone
>
IndexMut
<
usize
>
for
BlockVec
<
T
>
{
fn
index_mut
(
&
mut
self
,
index
:
usize
)
->
&
mut
T
{
let
block
=
index
>>
BLOCK_SHIFT
;
if
self
.v
.len
()
<=
block
{
self
.v
.resize
(
block
+
1
,
Vec
::
new
());
}
if
self
.v
[
block
]
.is_empty
()
{
self
.v
[
block
]
.resize
(
BLOCK_SIZE
,
T
::
default
());
}
&
mut
self
.v
[
block
][
index
&
BLOCK_MASK
]
}
}
impl
<
T
>
BlockVec
<
T
>
{
pub
fn
new
()
->
BlockVec
<
T
>
{
BlockVec
{
size
:
0
,
v
:
Vec
::
new
()
}
}
pub
fn
push
(
&
mut
self
,
value
:
T
)
{
let
i1
:
usize
=
self
.size
>>
BLOCK_SHIFT
;
if
i1
==
self
.v
.len
()
{
self
.v
.push
(
Vec
::
with_capacity
(
BLOCK_SIZE
));
}
assert
!
(
self
.v
[
i1
]
.len
()
==
(
self
.size
&
BLOCK_MASK
));
self
.v
[
i1
]
.push
(
value
);
self
.size
+=
1
}
pub
fn
len
(
&
self
)
->
usize
{
self
.size
}
pub
fn
clear
(
&
mut
self
)
{
self
.v
.clear
();
self
.size
=
0
;
}
}
struct
CachedGenerator
<
G
:
SoundGenerator
>
{
generator
:
G
,
start_time
:
usize
,
end_time
:
usize
}
pub
struct
SoundCache
<
G
:
SoundGenerator
>
{
generator
:
Option
<
Box
<
G
>>
,
generator
s
:
Vec
<
CachedGenerator
<
G
>>
,
tone
:
u8
,
start_time
:
usize
,
sound
:
BlockVec
<
G
::
Output
>
}
impl
<
G
:
SoundGenerator
>
SoundCache
<
G
>
{
pub
fn
new
(
tone
:
u8
)
->
SoundCache
<
G
>
{
SoundCache
{
generator
:
None
,
generator
s
:
Vec
::
new
()
,
tone
:
tone
,
start_time
:
0
,
sound
:
BlockVec
::
new
()
}
}
pub
fn
invalidate
(
&
mut
self
)
{
self
.generator
=
None
;
self
.generator
s
.clear
()
;
self
.sound
.clear
();
}
pub
fn
get_sample
(
&
mut
self
,
time
:
usize
,
param
:
&
G
::
Parameters
,
global
:
&
G
::
Global
)
->
Sample
{
let
end_time
=
self
.start_time
+
self
.sound
.len
();
if
self
.generator
.is_some
()
&&
time
>=
self
.start_time
&&
time
<
end_time
{
// Cached
return
self
.sound
[
time
-
self
.start_time
]
.into
();
// Find generator
let
mut
gi
:
usize
=
0
;
while
gi
<
self
.generators
.len
()
&&
self
.generators
[
gi
]
.end_time
<
time
{
gi
+=
1
;
}
if
gi
==
self
.generators
.len
()
||
time
<
self
.generators
[
gi
]
.start_time
{
self
.generators
.insert
(
gi
,
CachedGenerator
{
generator
:
G
::
new
(
param
,
self
.tone
,
time
,
global
),
start_time
:
time
,
end_time
:
time
});
}
if
self
.generator
.is_none
()
||
time
!=
end_time
{
// Re-initialize generator
self
.generator
=
Some
(
Box
::
new
(
G
::
new
(
param
,
self
.tone
,
time
,
global
)));
self
.start_time
=
time
;
self
.sound
.clear
();
// Generate next sample, if needed
if
self
.generators
[
gi
]
.end_time
==
time
{
self
.sound
[
time
]
=
self
.generators
[
gi
]
.generator
.produce_sample
();
self
.generators
[
gi
]
.end_time
+=
1
;
if
self
.generators
.len
()
>
gi
+
1
&&
self
.generators
[
gi
+
1
]
.start_time
==
self
.generators
[
gi
]
.end_time
{
// Merge generators
self
.generators
[
gi
+
1
]
.start_time
=
self
.generators
[
gi
]
.start_time
;
self
.generators
.remove
(
gi
);
}
}
// Next in sequence
let
sample
=
self
.generator
.as_mut
()
.unwrap
()
.produce_sample
();
self
.sound
.push
(
sample
);
sample
.into
()
// Return cached value
self
.sound
[
time
]
.into
()
}
}
synth/src/generate.rs
View file @
8516feba
...
...
@@ -63,7 +63,7 @@ pub trait SoundParameters {
pub
trait
SoundGenerator
{
type
Parameters
:
PartialEq
+
SoundParameters
;
type
Output
:
Copy
+
Into
<
Sample
>
;
type
Output
:
Default
+
Copy
+
Into
<
Sample
>
;
type
Global
:
Default
;
fn
new
(
param
:
&
Self
::
Parameters
,
tone
:
u8
,
time
:
usize
,
global
:
&
Self
::
Global
)
->
Self
;
...
...
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