jsyn
jsyn copied to clipboard
Passing a LineIn to PlayGrain
I am interested in trying a live input with PlayGrains, rather than a sample. I am guessing this would require e a new implementation of GrainSource, something like 'InputGrainSource', that extends GrainCommon. But I'm at a loss beyond that... ?
You could definitely implement a new GrainSource. Or you could use a SampleGrainSource. Then connect LineIn to a FixedMonoWriter and then queue the sample with a loop. Then it will pull grains randomly from recent input.
Thanks (and thanks for the link to Bencina's paper in the source -- I suppose I am going for what he refers to as the Tapped Delay Line version of GS), but I'm still a little unclear on the code. Would I need to create a new (subclass of) SampleGrainFarm, or rather use the current setup but call SampleGrainFarm.setSample() repeatedly ? Here's what I have so far (using the latter approach):
synth = JSyn.createSynthesizer();
synth.add( lineIn = new LineIn() );
synth.add( writer = new FixedRateMonoWriter() );
//sample = SampleLoader.loadFloatSample(sampleFile);
sample = new FloatSample( 44100 * DELAY_SECONDS, 1 );
writer.dataQueue.queueLoop( sample, 0, sample.getNumFrames() );
lineIn.output.connect( 0, writer.input, 1 );
lineIn.output.connect( 1, writer.input, 1 );
SampleGrainFarm sampleGrainFarm = new SampleGrainFarm();
synth.add(ramp = new ContinuousRamp());
sampleGrainFarm.setSample(sample);
ramp.output.connect(sampleGrainFarm.position);
grainFarm = sampleGrainFarm;
synth.add(grainFarm);
grainFarm.allocate(NUM_GRAINS);
synth.add(lineOut = new LineOut());
grainFarm.getOutput().connect(0, lineOut.input, 0);
grainFarm.getOutput().connect(0, lineOut.input, 1);
synth.start();
//synth.start(44100, AudioDeviceManager.USE_DEFAULT_DEVICE, 2, AudioDeviceManager.USE_DEFAULT_DEVICE, 2);
//synth.start(44100, AudioDeviceManager.USE_DEFAULT_DEVICE, 1, AudioDeviceManager.USE_DEFAULT_DEVICE, 2);
lineOut.start();
That looks right. But you need to also call writer.start() because it is not connected to anything. All sinks like LineIn and FixedRateMonoWriter need to be start()ed. I will add that to the unit documentation.
One problem with this is that you will get occasional glitches when the write index crosses the read index. So a better solution would be to create a new grain source that is like a FIFO. The reading from grains from the buffer will then be relative to the write pointer and avoid collisions.
You can write that. But I will consider this as a feature request and add it at some point.
Yes. I see what you mean with the clicks (a FIFO would be great)... But I also get a very different kind of sound (it is far more sparse, low-pitched) compared to my test with a sample using the same input, with the same interface parameters. Any idea why this would be?
Is the sample length different? Maybe the movement through the sample is scaled by the size.
Sorry, but you are asking if the length of the sample file is different than what... ?
Any hints on whats needed for the FIFO grain source?
I meant sample.getNumFrames().
For a FIFO grain source we need a Grain that reads data from a sample. The big difference is that the region that gets played does not collide with the write pointer, which will cause a glitch.
In SampleGrainFarm we need to set the position relative to the write pointer. Currently it does sampleGrainSource.setPosition(position.getValues()[i]);
We can calculate the current position of the write pointer from writePosition = writer.getFrameCount() % sample.getNumFrames()
We need a FifoGrainSource based on SampleGrainSource.
SampleGrainSource next() clips at PHASE_MAX. For FIFO we need to wrap around. I am also concerned about the clipping in SampleGrainSource.reset() that whole word looks suspect.
Sorry this vague. But I am really swamped at the moment.