bowed string (e.g. violin) synthesis algorithm - algorithm

Is there a well known algorithm for synthesising bowed string instruments (e.g. violins)?
I know for plucked strings (e.g. guitars) there's the karplus-strong algorithm, which I have succesfully implemented in the past.
Ideally I would like an algorithm describing a computer program for generating/synthesizing the digital signal.
For example, the karplus-strong algorithm can be summerized as follows:
Determine the period length of the frequency you want to synthesize and create a buffer of exactly that size
Fill the buffer with random numbers (white noise)
Iterate over the buffer, each time average each poitn with the next point then outputting it to the output stream.
Repeat for the desired amount of time while applying some damping
I wonder if something similar exists for bowed strings.
Footnote:
Now, I know nothing about the physics of how strings produce the sound, so I have no idea how one would derive such an algorithm. For the karplus-strong algorithm, I simply read it in the original paper and applied it "blindly". I would have never guessed that starting with a while noise and continuously damping it would produce a sound so similar to a plucked string.
EDIT:
As usual, the close parade has started.
Before voting to close this question, please consider the following:
This question is not about physics. It's not about the mechanics of the string vibration or interaction with the bow and air to produce the sound.
This question is about the existence of a specific well known algorithm to synthesize the sound. It's strictly a question about programming.

Weirdly i was able to find some stuff on this on the Stanford chuck website.
The code is written in a language called ChucK which is apparently specific for audio programming. You will have to run to use this code snippet. But here is its implementation in chuck:
// patch
Bowed bow => dac;
// scale
[0, 2, 4, 7, 8, 11] #=> int scale[];
// infinite time loop
while( true )
{
// set
Math.random2f( 0, 1 ) => bow.bowPressure;
Math.random2f( 0, 1 ) => bow.bowPosition;
Math.random2f( 0, 12 ) => bow.vibratoFreq;
Math.random2f( 0, 1 ) => bow.vibratoGain;
Math.random2f( 0, 1 ) => bow.volume;
// print
<<< "---", "" >>>;
<<< "bow pressure:", bow.bowPressure() >>>;
<<< "bow position:", bow.bowPosition() >>>;
<<< "vibrato freq:", bow.vibratoFreq() >>>;
<<< "vibrato gain:", bow.vibratoGain() >>>;
<<< "volume:", bow.volume() >>>;
// set freq
scale[Math.random2(0,scale.size()-1)] + 57 => Std.mtof => bow.freq;
// go
.8 => bow.noteOn;
// advance time
Math.random2f(.8, 2)::second => now;
}
Edit: The above is just the implementation, the source file for it is here.

Not an algorithm, but there's an open source library (under a very liberal license) that implements synthesis algorithms in C++ for several instruments, including bowed strings.
The Synthesis ToolKit (STK)
Official homepage: https://ccrma.stanford.edu/software/stk/
Github link: https://github.com/thestk/stk
Files with code relevant to synthesis of bowed string instruments:
include/Bowed.h
src/Bowed.cpp
include/BowTable.h
The comments in the code make references to two papers:
Efficient Simulation of the Reed-Bore and Bow-String Mechanisms
by Julius Smith (1986) (PDF)
On the Fundamentals of Bowed String Dynamics by Michael McIntyre & Jim Woodhouse (1979) (PDF)
Julius Smith also has information about bowed string synthesis available on his (standford) website:
Bowed Strings section of the "Physical Audio Signal Processing" book
MUS420 Lecture
Digital Waveguide Modeling of Bowed Strings

Related

does doc2vec(gensim) infer_vector needs window-size padded sentence?

According to the original paper Distributed Representations of Sentences and Documents, the inference on unseen paragraph can be done by
training “the inference stage” to get paragraph vectors D for new
paragraphs (never seen before) by adding more columns
in D and gradient descending on D while holding W, U, b
fixed
This inference stage can be done in gensim by infer_vector().
If I have window = 5 for doc2vec model, and attempts to infer paragraph with whose some sentences are len(sentence) < 5.
such as :
model = Doc2Vec(window=5)
paragraph = [['I', 'am', 'groot'], ['I', 'am', 'groot', 'I', 'am', 'groot']]
model.infer_vector(paragraph)
In this case, should I pre-pad my inferring vector with special NULL word symbol so that all length of sentences in the paragraph should be bigger than window size ?
such as :
paragraph = [['I', 'am', 'groot', NULL, NULL], ['I', 'am', 'groot', 'I', 'am', 'groot']]
You never need to do any explicit padding.
In the default and common Doc2Vec modes, if there's not enough context on either side of a focal word, the effective window simply shrinks on that side to match what is available.
(In the non-default dm=1, dm_concat=1 mode, there's automatic padding when necessary. But this mode results in larger, slower models requiring a lot more data to train, and whose value isn't very clear in any proven settings. That mode is unlikely to get good results except for advanced users with a lot of data and ability to tinker with non-default parameters.)
I found that gensim automatically pre-pads documents at both training and inferring stage.
gensim.models.doc2vec.train_document_dm_concat
null_word = model.vocab['\0']
pre_pad_count = model.window
post_pad_count = model.window
padded_document_indexes = (
(pre_pad_count * [null_word.index]) # pre-padding
+ [word.index for word in word_vocabs if word is not None] # elide out-of-Vocabulary words
+ (post_pad_count * [null_word.index]) # post-padding
)

pymc3 how to code multi-state discrete Bayes net CPT?

I'm trying to build a simple Bayesian network, where rain and sprinkler are the parents of wetgrass, but rain and sprinkler each have three (fuzzy-logic type rather rather than the usual two boolean) states, and wetgrass has two states (true/false). I can't find anywhere in the pymc3 docs what syntax to use to describe the CPTs for this -- I'm trying the following based on 2-state examples but it's not generalizing to three states the way I thought it would. Can anyone show the correct way to do this? (And also for the more general case where wetgrass has three states too.)
rain = mc.Categorical('rain', p = np.array([0.5, 0. ,0.5]))
sprinker = mc.Categorical('sprinkler', p=np.array([0.33,0.33,0.34]))
wetgrass = mc.Categorical('wetgrass',
mc.math.switch(rain,
mc.math.switch(sprinker, 10, 1, -4),
mc.math.switch(sprinker, -20, 1, 3),
mc.math.switch(sprinker, -5, 1, -0.5)))
[gives error at wetgrass definition:
Wrong number of inputs for Switch.make_node (got 4((, , , )), expected 3)
]
As I understand it - switch is a theano function similar to (b?a:b) in a C program; which is only doing a two way comparison. It's maybe possible to set up the CPT using a whole load of binary switches like this, but I really want to just give a 3D matrix CPT as the input as in BNT and other bayes net libraries. Is this currently possible ?
You can code a three-way switch using two individual switches:
tt.switch(sprinker == 0,
10
tt.switch(sprinker == 1, 1, -4))
But in general it is probably better to index into a table:
table = tt.constant(np.array([[...], [...]]))
value = table[rain, sprinker]

Train neural network with sine function

I want to train a neural network with the sine() function.
Currently I use this code and the (cerebrum gem):
require 'cerebrum'
input = Array.new
300.times do |i|
inputH = Hash.new
inputH[:input]=[i]
sinus = Math::sin(i)
inputH[:output] = [sinus]
input.push(inputH)
end
network = Cerebrum.new
network.train(input, {
error_threshold: 0.00005,
iterations: 40000,
log: true,
log_period: 1000,
learning_rate: 0.3
})
res = Array.new
300.times do |i|
result = network.run([i])
res.push(result[0])
end
puts "#{res}"
But it does not work, if I run the trained network I get some weird output values (instead of getting a part of the sine curve).
So, what I am doing wrong?
Cerebrum is a very basic and slow NN implementation. There are better options in Ruby, such as ruby-fann gem.
Most likely your problem is the network is too simple. You have not specified any hidden layers - it looks like the code assigns a default hidden layer with 3 neurons in it for your case.
Try something like:
network = Cerebrum.new({
learning_rate: 0.01,
momentum: 0.9,
hidden_layers: [100]
})
and expect it to take forever to train, plus still not be very good.
Also, your choice of 300 outputs is too broad - to the network it will look mostly like noise and it won't interpolate well between points. A neural network does not somehow figure out "oh, that must be a sine wave" and match to it. Instead it interpolates between the points - the clever bit happens when it does so in multiple dimensions at once, perhaps finding structure that you could not spot so easily with a manual inspection. To give it a reasonable chance of learning something, I suggest you give it much denser points e.g. where you currently have sinus = Math::sin(i) instead use:
sinus = Math::sin(i.to_f/10)
That's still almost 5 iterations through the sine wave. Which should hopefully be enough to prove that the network can learn an arbitrary function.

Selecting only a small amount of trials in a possibly huge condition file in a pseudo-randomized way

I am using the PsychoPy Builder and have used the code only rudimentary.
Now I'm having a problem for which I think coding is inevitable, but I have no idea how to do it and so far, I didn't find helpful answers in the net.
I have an experiment with pictures of 3 valences (negative, neutral, positive).
In one of the corners of the pictures, additional pictures (letters and numbers) can appear (randomly in one of the 4 positions) in random latencies.
All in all, with all combinations (taken the identity of the letters/numbers into account), I have more than 2000 trial possibilities.
But I only need 72 trials, with the condition that each valence appears 24 times (or: each of the 36 pictures 2 times) and each latency 36 times. Thus, the valence and latency should be counterbalanced, but the positions and the identities of the letters and numbers can be random. However, in a specific rate, (in 25% of the trials) no letters/ numbers should apear in the corners.
Is there a way to do it?
Adding a pretty simple code component in builder will do this for you. I'm a bit confused about the conditions, but you'll probably get the general idea. Let's assume that you have your 72 "fixed" conditions in a conditions file and a loop with a routine that runs for each of these conditions.
I assume that you have a TextStim in your stimulus routine. Let's say that you called it 'letternumber'. Then the general strategy is to pre-compute a list of randomized characters and positions for each of the 72 trials and then just display them as we move through the experiment. To do this, add a code component to the top of your stimulus routine and add under "begin experiment":
import random # we'll use this module to pick random elements from below
# Indicator sequence, specifying whether letter/number should be shown. False= do not show. True = do show.
show_letternumber = [False] * 18 + [True] * 54 # 18/72=25%, 54/72=75%.
random.shuffle(show_letternumber)
# Sets of letters and numbers to present
char_set = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g'] # ... and so on.
char_trial = [random.choice(char_set) if show_char else '' for show_char in char_set] # list with characters
# List of positions
pos_set = [(0.5, 0.5),(-0.5, 0.5),(-0.5,-0.5),(0.5, -0.5)] # coordinates of your four corners
pos_trial = [random.choice(pos_set) for char in char_trial]
Then under "begin routine" in the code component, set the lettersnumbers to show the value of character_trial for that trial and at the position in pos_trial.
letternumbers.pos = pos_trial[trials.thisN] # set position. trials.thisN is the current trial number
letternumbers.text = char_trial[trials.thisN] # set text
# Save to data/log
trials.addData('pos', pos_trial[trials.thisN])
trials.addData('char', char_trial[trials.thisN])
You may need to tick "set every repeat" for the lettersnumbers component in Builder for the text to actually show.
Here is a strategy you could try, but as I don't use builder I can't integrate it into that work flow.
Prepare a list that has the types of trials you want in the write numbers. You could type this by hand if needed. For example mytrials = ['a','a',...'d','d'] where those letters represent some label for the combination of trial types you want.
Then open up the console and permute that list (i.e. shuffle it).
import random
random.shuffle(mytrials)
That will shift the mytrials around. You can see that by just printing that. When you are happy with that paste that into your code with some sort of loop like
t in mytrials:
if t == 'a':
<grab a picture of type 'a'>
elseif t == 'b':
<grab a picture of type 'b'>
else:
<grab a picture of type 'c'>
<then show the picture you grabbed>
There are programmatic ways to build the list with the right number of repeats, but for what you are doing it may be easier to just get going with a hand written list, and then worry about making it fancier once that works.

Cake Comparison Algorithm

This is literally about comparing cakes. My friend is having a cupcake party with the goal of determining the best cupcakery in Manhattan. Actually, it's much more ambitious than that. Read on.
There are 27 bakeries, and 19 people attending (with maybe one or two no-shows). There will be 4 cupcakes from each bakery, if possible including the staples -- vanilla, chocolate, and red velvet -- and rounding out the 4 with wildcard flavors. There are 4 attributes on which to rate the cupcakes: flavor, moistness, presentation (prettiness), and general goodness. People will provide ratings on a 5-point scale for each attribute for each cupcake they sample. Finally, each cupcake can be cut into 4 or 5 pieces.
The question is: what is a procedure for coming up with a statistically meaningful ranking of the bakeries for each attribute, and for each flavor (treating "wildcard" as a flavor)? Specifically, we want to rank the bakeries 8 times: for each flavor we want to rank the bakeries by goodness (goodness being one of the attributes), and for each attribute we want to rank the bakeries across all flavors (ie, independent of flavor, ie, aggregating over all flavors). The grand prize goes to the top-ranked bakery for the goodness attribute.
Bonus points for generalizing this, of course.
This is happening in about 12 hours so I'll post as an answer what we ended up doing if no one answers in the meantime.
PS: Here's the post-party blog post about it: http://gracenotesnyc.com/2009/08/05/gracenotes-nycs-cupcake-cagematch-the-sweetest-battle-ever/
Here's what we ended up doing. I made a huge table to collect everyone's ratings at http://etherpad.com/sugarorgy (Revision 25, just in case it gets vandalized with me adding this public link to it) and then used the following Perl script to parse the data into a CSV file:
#!/usr/bin/env perl
# Grabs the cupcake data from etherpad and parses it into a CSV file.
use LWP::Simple qw(get);
$content = get("http://etherpad.com/ep/pad/export/sugarorgy/latest?format=txt");
$content =~ s/^.*BEGIN_MAGIC\s*//s;
$content =~ s/END_MAGIC.*$//s;
$bakery = "none";
for $line (split('\n', $content)) {
next if $line =~ /sar kri and deb/;
if ($line =~ s/bakery\s+(\w+)//) { $bakery = $1; }
$line =~ s/\([^\)]*\)//g; # strip out stuff in parens.
$line =~ s/^\s+(\w)(\w)/$1 $2/;
$line =~ s/\-/\-1/g;
$line =~ s/^\s+//;
$line =~ s/\s+$//;
$line =~ s/\s+/\,/g;
print "$bakery,$line\n";
}
Then I did the averaging and whatnot in Mathematica:
data = Import["!~/svn/sugar.pl", "CSV"];
(* return a bakery's list of ratings for the given type of cupcake *)
tratings[bak_, t_] := Select[Drop[First#Select[data,
#[[1]]==bak && #[[2]]==t && #[[3]]=="g" &], 3], #!=-1&]
(* return a bakery's list of ratings for the given cupcake attribute *)
aratings[bak_, a_] := Select[Flatten[Drop[#,3]& /#
Select[data, #[[1]]==bak && #[[3]]==a&]], #!=-1&]
(* overall rating for a bakery *)
oratings[bak_] := Join ## (tratings[bak, #] & /# {"V", "C", "R", "W"})
bakeries = Union#data[[All, 1]]
SortBy[{#, oratings##, Round[Mean#oratings[#], .01]}& /# bakeries, -#[[3]]&]
The results are at the bottom of http://etherpad.com/sugarorgy.
Perhaps reading about voting systems will be helpful. PS: don't take whatever is written on Wikipedia as "good fish". I have found factual errors in advanced topics there.
Break the problem up into sub-problems.
What's the value of a cupcake? A basic approach is "the average of the scores." A slightly more robust approach may be "the weighted average of the scores." But there may be complications beyond that... a cupcake with 3 goodness and 3 flavor may be 'better' than one with 5 flavor and 1 goodness, even if flavor and goodness have equal weight (IOW, a low score may have a disproportionate effect).
Make up some sample cupcake scores (specifics! Cover the normal scenarios and a couple weird ones), and estimate what you think a reasonable "overall" score would be if you had an ideal algorithm. Then, use that data to reverse engineer the algorithm.
For example, a cupcake with goodness 4, flavor 3, presentation 1 and moistness 4 might deserve a 4 overall, while one with goodness 4, flavor 2, presentation 5, and moistness 4 might only rate a 3.
Next, do the same thing for the bakery. Given a set of cupcakes with a range of scores, what would an appropriate rating be? Then, figure out the function that will give you that data.
The "goodness" ranking seems a bit odd, as it seems like it's a general rating, and so having it in there is already the overall score, so why calculate an overall score?
If you had time to work with this, I'd always suggest capturing the raw data, and using that as a basis to do more detailed analysis, but I don't think that's really relevant here.
Perhaps this is too general for you, but this type of problem can be approached using Conjoint Analysis (link text). A R package for implementing this is bayesm(link text).
If you can write SQL, you could make a little database and write some queries. It should not be that difficult.
e.g. select sum(score) / count(score) as finalscore, bakery, flavour from tables where group by bakery, flavour

Resources