docs and warnings fixed

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

View File

@ -26,9 +26,10 @@
using namespace spiralcore; using namespace spiralcore;
using namespace std; using namespace std;
static void _process(void *c) { static void* _process(void *c) {
process_thread *p=(process_thread*)c; process_thread *p=(process_thread*)c;
p->process(); p->process();
return NULL;
} }
process_thread::process_thread() : 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(); ((block_stream::worker *)p)->run();
return NULL;
} }
block_stream::worker::worker(u32 id, window *w) : 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++) { for(u32 i=0; i<sfinfo.frames; i++) {
s[i]=0; s[i]=0;
// mix down stereo to mono // 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]; s[i]+=temp[i*sfinfo.channels + j];
} }
} }
@ -267,8 +267,17 @@ void brain::build_synapses_fixed(search_params &params) {
u32 num_synapses = NUM_FIXED_SYNAPSES; u32 num_synapses = NUM_FIXED_SYNAPSES;
if (num_synapses>=m_blocks.size()) num_synapses=m_blocks.size()-1; 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) { for (auto &i:m_blocks) {
if (update_tick>update_period) {
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100)); status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
update_tick=0;
}
update_tick++;
u32 index = 0; u32 index = 0;
vector<pair<u32,double>> collect; vector<pair<u32,double>> collect;

View File

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

View File

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