mirror of
https://gitlab.com/then-try-this/samplebrain.git
synced 2025-05-12 10:37:20 +00:00
docs and warnings fixed
This commit is contained in:
parent
7cb3adf147
commit
6bb5732c70
@ -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() :
|
||||||
|
@ -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) :
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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));
|
m_blocks.push_back(block(m_blocks.size(),s.m_filename,region,44100,m_window,ditchpcm));
|
||||||
pos += (m_block_size-m_overlap);
|
pos += (m_block_size-m_overlap);
|
||||||
|
|
||||||
// periodic progress update
|
// periodic progress update
|
||||||
if (update_tick>update_period) {
|
if (update_tick>update_period) {
|
||||||
status::update("processing sample %d: %d%%",count,(int)(pos/(float)s.m_sample.get_length()*100));
|
status::update("processing sample %d: %d%%",count,(int)(pos/(float)s.m_sample.get_length()*100));
|
||||||
update_tick=0;
|
update_tick=0;
|
||||||
@ -248,16 +248,16 @@ void brain::build_synapses_thresh(search_params ¶ms, double thresh) {
|
|||||||
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
|
status::update("building synapses %d%%",(int)(outer_index/(float)brain_size*100));
|
||||||
for (auto &j : m_blocks) {
|
for (auto &j : m_blocks) {
|
||||||
if (index!=outer_index) {
|
if (index!=outer_index) {
|
||||||
// collect connections that are under threshold in closeness
|
// collect connections that are under threshold in closeness
|
||||||
double diff = i.compare(j,params);
|
double diff = i.compare(j,params);
|
||||||
if (diff<err) {
|
if (diff<err) {
|
||||||
i.get_synapse().push_back(index);
|
i.get_synapse().push_back(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
++outer_index;
|
++outer_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void brain::build_synapses_fixed(search_params ¶ms) {
|
void brain::build_synapses_fixed(search_params ¶ms) {
|
||||||
@ -267,8 +267,17 @@ void brain::build_synapses_fixed(search_params ¶ms) {
|
|||||||
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) {
|
||||||
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;
|
u32 index = 0;
|
||||||
vector<pair<u32,double>> collect;
|
vector<pair<u32,double>> collect;
|
||||||
|
|
||||||
|
@ -27,48 +27,42 @@ 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 {
|
||||||
}
|
// have to split data over boundary
|
||||||
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;
|
||||||
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;
|
||||||
memcpy(&(m_buffer[m_write_pos]), src, first);
|
m_write_pos &= m_size_mask;
|
||||||
m_write_pos += first;
|
|
||||||
m_write_pos &= m_size_mask;
|
memcpy(&(m_buffer[m_write_pos]), &src[first], second);
|
||||||
|
m_write_pos += second;
|
||||||
memcpy(&(m_buffer[m_write_pos]), &src[first], second);
|
m_write_pos &= m_size_mask;
|
||||||
m_write_pos += second;
|
}
|
||||||
m_write_pos &= m_size_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -79,38 +73,34 @@ 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;
|
|
||||||
|
memcpy(dest, &(m_buffer[m_read_pos]), first);
|
||||||
memcpy(dest, &(m_buffer[m_read_pos]), first);
|
m_read_pos += first;
|
||||||
m_read_pos += first;
|
m_read_pos &= m_size_mask;
|
||||||
m_read_pos &= m_size_mask;
|
|
||||||
|
memcpy(&dest[first], &(m_buffer[m_read_pos]), second);
|
||||||
memcpy(&dest[first], &(m_buffer[m_read_pos]), second);
|
m_read_pos += second;
|
||||||
m_read_pos += second;
|
m_read_pos &= m_size_mask;
|
||||||
m_read_pos &= m_size_mask;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
158
docs/manual.md
158
docs/manual.md
@ -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:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
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.
|

|
||||||
|
|
||||||
|
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
|

|
||||||
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
|

|
||||||
|
|
||||||
|
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
BIN
docs/pics/bar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
BIN
docs/pics/braincontents.png
Normal file
BIN
docs/pics/braincontents.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
BIN
docs/pics/braintweaks.png
Normal file
BIN
docs/pics/braintweaks.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 249 KiB |
BIN
docs/pics/mix.png
Normal file
BIN
docs/pics/mix.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
BIN
docs/pics/screenshot.jpg
Normal file
BIN
docs/pics/screenshot.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 248 KiB |
BIN
docs/pics/targetsound.png
Normal file
BIN
docs/pics/targetsound.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
Loading…
x
Reference in New Issue
Block a user