docs and warnings fixed

This commit is contained in:
Dave Griffiths 2022-09-10 14:05:45 +01:00
parent 073c54c6a7
commit f58602ecf4
11 changed files with 160 additions and 126 deletions

View File

@ -26,9 +26,10 @@
using namespace spiralcore;
using namespace std;
static void _process(void *c) {
static void* _process(void *c) {
process_thread *p=(process_thread*)c;
p->process();
return NULL;
}
process_thread::process_thread() :

View File

@ -113,8 +113,9 @@ const block &block_stream::get_block(u32 index) const {
//-----------------------------------------------------------
void _run_worker(void *p) {
void *_run_worker(void *p) {
((block_stream::worker *)p)->run();
return NULL;
}
block_stream::worker::worker(u32 id, window *w) :

View File

@ -53,7 +53,7 @@ void brain::load_sound(std::string filename, stereo_mode mode) {
for(u32 i=0; i<sfinfo.frames; i++) {
s[i]=0;
// mix down stereo to mono
for(u32 j = 0; j < sfinfo.channels; j++) {
for(s32 j = 0; j < sfinfo.channels; j++) {
s[i]+=temp[i*sfinfo.channels + j];
}
}
@ -135,7 +135,7 @@ void brain::chop_and_add(sound &s, u32 count, bool ditchpcm) {
m_blocks.push_back(block(m_blocks.size(),s.m_filename,region,44100,m_window,ditchpcm));
pos += (m_block_size-m_overlap);
// periodic progress update
// periodic progress update
if (update_tick>update_period) {
status::update("processing sample %d: %d%%",count,(int)(pos/(float)s.m_sample.get_length()*100));
update_tick=0;
@ -248,16 +248,16 @@ void brain::build_synapses_thresh(search_params &params, double thresh) {
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
for (auto &j : m_blocks) {
if (index!=outer_index) {
// collect connections that are under threshold in closeness
double diff = i.compare(j,params);
if (diff<err) {
i.get_synapse().push_back(index);
}
// collect connections that are under threshold in closeness
double diff = i.compare(j,params);
if (diff<err) {
i.get_synapse().push_back(index);
}
}
++index;
}
++outer_index;
}
}
}
void brain::build_synapses_fixed(search_params &params) {
@ -267,8 +267,17 @@ void brain::build_synapses_fixed(search_params &params) {
u32 num_synapses = NUM_FIXED_SYNAPSES;
if (num_synapses>=m_blocks.size()) num_synapses=m_blocks.size()-1;
// need to stop the progress updates flooding osc
u32 update_period = 100;
u32 update_tick = 0;
for (auto &i:m_blocks) {
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
if (update_tick>update_period) {
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
update_tick=0;
}
update_tick++;
u32 index = 0;
vector<pair<u32,double>> collect;

View File

@ -27,48 +27,42 @@ ring_buffer::ring_buffer(unsigned int size):
m_write_pos(0),
m_size(size),
m_size_mask(size-1),
m_buffer(NULL)
{
m_buffer(NULL) {
m_buffer = new char[m_size];
memset(m_buffer,'Z',m_size);
}
ring_buffer::~ring_buffer()
{
ring_buffer::~ring_buffer() {
delete[] m_buffer;
}
bool ring_buffer::write(char *src, unsigned int size)
{
bool ring_buffer::write(char *src, unsigned int size) {
//cerr<<"write pos: "<<m_write_pos<<endl;
unsigned int space=write_space();
if (space<size)
{
cerr<<"ringbuffer ran out of space, needed: "<<size<<" have: "<<space<<endl;
return false;
}
if (space<size) {
//cerr<<"ringbuffer ran out of space, needed: "<<size<<" have: "<<space<<endl;
return false;
}
if (size<m_size-m_write_pos)
{
//cerr<<"written to: "<<m_write_pos<<endl;
memcpy(&(m_buffer[m_write_pos]), src, size);
m_write_pos += size;
m_write_pos &= m_size_mask;
}
else // have to split data over boundary
{
unsigned int first = m_size-m_write_pos;
unsigned int second = (m_write_pos+size) & m_size_mask;
memcpy(&(m_buffer[m_write_pos]), src, first);
m_write_pos += first;
m_write_pos &= m_size_mask;
memcpy(&(m_buffer[m_write_pos]), &src[first], second);
m_write_pos += second;
m_write_pos &= m_size_mask;
}
if (size<m_size-m_write_pos) {
//cerr<<"written to: "<<m_write_pos<<endl;
memcpy(&(m_buffer[m_write_pos]), src, size);
m_write_pos += size;
m_write_pos &= m_size_mask;
} else {
// have to split data over boundary
unsigned int first = m_size-m_write_pos;
unsigned int second = (m_write_pos+size) & m_size_mask;
memcpy(&(m_buffer[m_write_pos]), src, first);
m_write_pos += first;
m_write_pos &= m_size_mask;
memcpy(&(m_buffer[m_write_pos]), &src[first], second);
m_write_pos += second;
m_write_pos &= m_size_mask;
}
return true;
}
@ -79,38 +73,34 @@ bool ring_buffer::read(char *dest, unsigned int size)
unsigned int space=read_space();
if (space==0 || size>m_size) return false;
if (size<m_size-m_read_pos)
{
if (size<m_size-m_read_pos) {
//cerr<<"reading from: "<<m_read_pos<<endl;
memcpy(dest, &(m_buffer[m_read_pos]), size);
m_read_pos += size;
m_read_pos &= m_size_mask;
}
else // have to split data over boundary
{
unsigned int first = m_size-m_read_pos;
unsigned int second = (m_read_pos+size) & m_size_mask;
memcpy(dest, &(m_buffer[m_read_pos]), first);
m_read_pos += first;
m_read_pos &= m_size_mask;
memcpy(&dest[first], &(m_buffer[m_read_pos]), second);
m_read_pos += second;
m_read_pos &= m_size_mask;
}
} else {
// have to split data over boundary
unsigned int first = m_size-m_read_pos;
unsigned int second = (m_read_pos+size) & m_size_mask;
memcpy(dest, &(m_buffer[m_read_pos]), first);
m_read_pos += first;
m_read_pos &= m_size_mask;
memcpy(&dest[first], &(m_buffer[m_read_pos]), second);
m_read_pos += second;
m_read_pos &= m_size_mask;
}
return true;
}
void ring_buffer::dump()
{
void ring_buffer::dump() {
for (unsigned int i=0; i<m_size; i++) cerr<<m_buffer[i];
cerr<<endl;
}
unsigned int ring_buffer::write_space()
{
unsigned int ring_buffer::write_space() {
unsigned int read = m_read_pos;
unsigned int write = m_write_pos;
@ -119,8 +109,7 @@ unsigned int ring_buffer::write_space()
return m_size - 1;
}
unsigned int ring_buffer::read_space()
{
unsigned int ring_buffer::read_space() {
unsigned int read = m_read_pos;
unsigned int write = m_write_pos;

View File

@ -1,17 +1,31 @@
# Samplebrain Manual
A custom sample mashing app designed by Aphex Twin.
Samplebrain chops samples up into a 'brain' of interconnected small
sections called blocks which are connected into a network by
similarity. It processes a target sample, chopping it up into blocks
in the same way, and tries to match each block with one in it's brain
to play in realtime.
This allows you to interpret a sound with a different one. Over time
developing it, we gradually added more and more tweakable parameters
until it became slightly out of control.
## Brain tweaks:
![](pics/braintweaks.png)
These settings control how the block search works.
### fft / mfcc
Choose whether to search using FFT (raw frequency analysis) or MFCC
(Mel-frequency cepstral coefficients) which are higher order paramters
that attempt to model perception of sound. MFCC is usually a bit
better, but it depends on what you are doing, you can blend between
them to use a mix. Setting this to 0% or 100% switches off the other
search option, so is a bit more CPU friendly.
Choose whether to match blocks using FFT (raw frequency analysis) or
MFCC (Mel-frequency cepstral coefficients, parameters that attempt to
model perception of sound). Which is best depends on the sounds you
are using, so you can blend between them to use a mix. Setting this to
0% or 100% switches off the other search option, so is a bit more CPU
friendly.
### freq & dynamics / freq only
@ -21,76 +35,85 @@ want the first option.
### fft subsection
When using FFT mode you can select a subrange of the (100) frequency
bins to use for scoring potential blocks, potentially allowing you to
target a specific frequency range. Not terribly useful in practice.
You can select a subrange of the (100) frequency bins we use for
scoring potential blocks, potentially allowing you to target a
specific frequency range. Not that useful in practice so far.
### novelty
One thing that tends to happen is that the same block or set of blocks
can be overused if there isn't enough variation in the brain
blocks. Sometimes we want to bias the selection against reuse, so
novelty biases the selection away from similarity - if you turn it all
the way up it will ignore the target completely and just play the
least used ones in some odd semi-random order.
Often the same block or set of blocks tend to be overused if there
isn't enough variation in the brain. You can use 'novelty' to bias the
selection away from similarity, and prioritise similar blocks we
haven't used yet.
### boredom
This increases the speed at which novelty wears off, creating a wider
spread of possible blocks. Not quite clear exactly why this is
different to increasing novelty, but it sounds different.
spread of possible blocks to be used.
If you turn novelty and boredom all the way up it will ignore the
target completely and just play brain samples in some odd semi-random
order.
### stickyness
If the error is under this threshold, play the next block in the brain
rather than the closest. This will have the effect of elongating
chunks of brain samples that you hear.
If the error of the next block in the sequence after the one we have
just used is under the stickyness threshold, we will use that rather
than the closest in our search. This will have the effect of
elongating chunks of brain samples that you hear.
### search stretch
Repeats blocks in the target a fixed amount, like a simple timestretch
- in synaptic mode this gives the system repeated attempts to find a
closer match.
- using the above controls it won't necessarily repeat the same brain
block, and in synaptic mode (see below) this gives the system repeated
attempts to find a closer match in the network.
### algorithm
* basic
Searches all samples in the brain, and uses the closest match.
Searches all sample blocks. Not usable with large brains.
* reversed
Searches all samples in the brain, and uses the least closest
match. In practice this needs work, as it tends to select silent or
very quiet blocks.
Searches all samples in the brain, but selects the least closest match
instead of the closest. In practice this needs work, as silent or very
quiet blocks tend to be the least similar.
* synaptic
As brains get larger, we get more blocks, and they get slower to
search. This mode provides a constant search time over arbitrarily
huge brains. When generating the brains we connect them together into
a network via similarity (via connections called synapses). We keep a
position in the network and only search the nearby blocks - this
assumes that sounds tend to change gradually, or at least more
gradually than the small block lengths.
As brains get larger with more blocks, they get slower to search. This
mode provides a constant search time over arbitrarily large brains. To
do this we connect the blocks together into a network via similarity
(via connections called synapses). We store a current "playback
position" in the network and only search the nearby blocks the playing
block is connected to. This assumes that sounds tend to change
gradually, or at least more gradually than the smaller block lengths.
This can leads to the output changing with each repetition of the
target, as we wander around the synapse network.
* slide
Similar to synaptic but if we can't find a close enough match (based
on synaptic slide error) we stretch the target, repeating blocks until
we land on a block that is close enough. This mode warps the timing of
the target.
Similar to synaptic mode above but if we can't find a close enough
match (based on synaptic slide error) we repeat the target block
again, stretching it until we land on a block that is close
enough. This mode unpredictably warps the timing of the target sound.
### num synapses
How many connections to check in synaptic or slide mode.
How many connections to check in synaptic or slide mode, up to a
maximum of 1000 - they are ordered by closeness.
### synaptic slide error
The acceptable error to consider a block as "close enought" in slide mode.
The acceptable error to consider a block as "close enough" in slide mode.
## Target sound:
![](pics/targetsound.png)
These settings control how the target sound is broken up into blocks.
### load target
@ -100,15 +123,16 @@ Load a target sound to try and match
### block size
The size of the blocks in samples. This does not need to match the
brain block size, but it probably should.
brain block size.
### block overlap
Percentage overlap in blocks.
Proportion to overlap the block generation.
### window shape
The shape of the window - "dodgy" is actually box.
The windowing function for the target blocks, the volume shape given
to them before use - "dodgy" is actually rectangle, so no shaping.
### (re)generate blocks
@ -116,12 +140,14 @@ Compute the target blocks.
### use mic input
Attempts to stream blocks live from the microphone. I think this is
broken at present.
Attempts to stream blocks live from the microphone. This has not been
tested fully.
## Mix:
These are settings that happen after the search.
![](pics/mix.png)
These are settings that control things happening after the search.
### autotune
@ -129,21 +155,24 @@ Attempt to pitch bend the chosen brain block to better match the target.
### normalised
Mix in normalised brain blocks - removing all dynamics. Might work
with frequency only search.
Mix in normalised brain blocks - removing all dynamics. Designed to
work with frequency only search.
### brain / target
Mix in the target blocks to the output - for cheating, or testing purposes.
Mix in the target blocks to the output - for cheating, or testing
purposes.
### stereo mode
Run everything once for left and again for right speaker.
Run separate searches for left and again for right speaker.
## Brain contents
These settings allow you to build a brain of samples, and switch in
and out specific samples during playback.
![](pics/braincontents.png)
These settings allow you to build your sample brain, and switch in and
out specific samples live during playback.
### all/none
@ -158,15 +187,16 @@ in one go.
### block size
The size of the blocks in samples. This does not need to match the
target block size, but it probably should.
target block size.
### block overlap
Percentage overlap in blocks.
Proportion to overlap the block generation.
### window shape
The shape of the window - "dodgy" is actually box.
The windowing function for the brain blocks, the volume shape given
to them before use - "dodgy" is actually rectangle, so no shaping.
### (re)generate blocks
@ -178,15 +208,17 @@ You can save and load brains separately to the targets.
## Lower bar
General playback settings
![](pics/bar.png)
General playback settings.
### play/pause/record/stop
Start/stop and record
Start/stop and record.
### volume
Global volume
Global volume.
### load/save session
@ -196,4 +228,6 @@ Load and save the entire session.
This allows you to control multiple instances of samplebrain over the
network all running their own brains simultaneously. This feature has
not been tested well!
not been tested well.

BIN
docs/pics/bar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/pics/braincontents.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
docs/pics/braintweaks.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

BIN
docs/pics/mix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/pics/screenshot.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
docs/pics/targetsound.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB