jsyn icon indicating copy to clipboard operation
jsyn copied to clipboard

Passing a LineIn to PlayGrain

Open dhowe opened this issue 7 years ago • 8 comments

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

dhowe avatar Nov 22 '16 10:11 dhowe

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.

philburk avatar Nov 24 '16 01:11 philburk

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();

dhowe avatar Nov 26 '16 06:11 dhowe

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.

philburk avatar Nov 26 '16 20:11 philburk

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?

dhowe avatar Nov 27 '16 04:11 dhowe

Is the sample length different? Maybe the movement through the sample is scaled by the size.

philburk avatar Nov 28 '16 17:11 philburk

Sorry, but you are asking if the length of the sample file is different than what... ?

dhowe avatar Nov 28 '16 18:11 dhowe

Any hints on whats needed for the FIFO grain source?

dhowe avatar Jan 13 '17 03:01 dhowe

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.

philburk avatar Jan 14 '17 03:01 philburk