0

I'm working on p5.js web editor to create a program that from a an input audio files, divide it in segment, random shuffle them, and recompose them. this part of the program is working well and the new output audio generate with random order segments is played. the problem is that I can't add the audio effects to the new audio source from the output buffer.

let audioFile;
let audioBuffer;
let segmentLength = 100; // length of each segment in milliseconds
let segments = [];
let audioContext;

function preload() {
  audioFile = loadSound('sounds/02ContortYourself.mp3');
}

function setup() {
  createCanvas(400, 400);
  
  // Create a new AudioContext object
  audioContext = new AudioContext();
  
  // Load the audio file and decode it into an AudioBuffer object
  audioFile.play();
  audioBuffer = audioFile.buffer;
  
  // Split the audio buffer into segments of the specified length
  let numSegments = Math.ceil(audioBuffer.duration * 1000 / segmentLength);
  for(let i = 0; i < numSegments; i++) {
    let go = i * segmentLength / 1000;
    let end = go + segmentLength / 1000;
    let segment = audioBuffer.getChannelData(0).subarray(go * audioBuffer.sampleRate, end * audioBuffer.sampleRate);
    segments.push(segment);
    
    // Print the length of the segment in milliseconds
    console.log(`Segment ${i}: ${segmentLength}ms`);
  }
  
  // Shuffle the segments array using the Fisher-Yates shuffle algorithm
  for (let i = segments.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [segments[i], segments[j]] = [segments[j], segments[i]];
  }
  
  // Create a new audio buffer for the output song
  let outputBuffer = new AudioBuffer({
    numberOfChannels: 1,
    length: audioBuffer.length,
    sampleRate: audioBuffer.sampleRate
  });
  
  // Copy each segment into the output buffer in their shuffled order
  for (let i = 0; i < segments.length; i++) {
    let offset = i * segmentLength * audioBuffer.sampleRate / 1000;
    outputBuffer.copyToChannel(segments[i], 0, offset);
  }
  
  // Create a new audio source from the output buffer and play it
  let outputSource = new AudioBufferSourceNode(audioContext, { buffer: outputBuffer });
  outputSource.connect(audioContext.destination);
  outputSource.start();
}

my idea is to add the effects to the outputSource before it is played by the start function. in this way, in the next pahase of the project, I think I can easily implement on/off button to apply or not the effects.

this is what I have tried but it is not working.

let audioFile;
let audioBuffer;
let segmentLength = 100; // length of each segment in milliseconds
let patternLength = 15; // length of each pattern in segments
let numPatterns; // number of patterns in the final output
let numSegments; // total number of segments in the output
let segments = [];
let patterns = [];
let audioContext;

function preload() {
  console.log('Loading audio file...');
  audioFile = loadSound('sounds/02ContortYourself.mp3', onAudioLoaded, onAudioLoadError);
}

function onAudioLoaded() {
  console.log('Audio file loaded successfully!');
  
  // Create a new AudioContext object
  audioContext = new AudioContext();
  
  // Get the decoded audio buffer from the loaded audio file
  audioBuffer = audioFile.buffer;
  
  // Calculate the maximum number of patterns and segments that fit within 1 minute
  let maxDuration = 60; // maximum duration of the output song in seconds
  numPatterns = Math.floor(maxDuration * 1000 / (segmentLength * patternLength));
  numSegments = numPatterns * patternLength;
  
  // Split the audio buffer into segments of the specified length, up to the maximum duration
  for(let i = 0; i < numSegments; i++) {
    let go = i * segmentLength / 1000;
    let end = go + segmentLength / 1000;
    let segment = audioBuffer.getChannelData(0).subarray(go * audioBuffer.sampleRate, end * audioBuffer.sampleRate);
    segments.push(segment);
    
    // Print the length of the segment in milliseconds
    console.log(`Segment ${i}: ${segmentLength}ms`);
  }
  
  // Shuffle the segments array using the Fisher-Yates shuffle algorithm
  for (let i = segments.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [segments[i], segments[j]] = [segments[j], segments[i]];
  }
  
  // Group segments into patterns
  for (let i = 0; i < numPatterns; i++) {
    let pattern = [];
    for (let j = 0; j < patternLength; j++) {
      pattern.push(segments[i * patternLength + j]);
    }
    patterns.push(pattern);
  }
  
  // Arrange patterns in a specific sequence
  let patternSequence = [0, 0, 2, 2, 1, 1, 3, 3, 3, 3, 2, 0, 1]; // example pattern sequence
  let outputSegments = [];
  while (outputSegments.length < numSegments) {
    outputSegments = outputSegments.concat(patternSequence.map(index => patterns[index]).flat());
  }
  outputSegments = outputSegments.slice(0, numSegments);
  
  // Create a new audio buffer for the output song
  let outputBuffer = new AudioBuffer({
    numberOfChannels: 1,
    length: outputSegments.length * segmentLength * audioBuffer.sampleRate / 1000,
    sampleRate: audioBuffer.sampleRate
  });
  
  // Copy each segment into the output buffer in their arranged order
  for (let i = 0; i < outputSegments.length; i++) {
    let offset = i * segmentLength * audioBuffer.sampleRate / 1000;
    outputBuffer.copyToChannel(outputSegments[i], 0, offset);
  }
  
  // Create a new audio source from the output buffer and play it
  let outputSource = new AudioBufferSourceNode(audioContext, { buffer: outputBuffer });
  outputSource.connect(audioContext.destination);
  
  // Resume the audio context to allow audio playback
  audioContext.resume();
  
  // Apply a reverb effect to the output source
  let reverb = new p5.Reverb();
  reverb.set(3, 2); // set the decay time to 3 seconds and the wet/dry mix to 2:1
  outputSource.connect(reverb);
  reverb.connect(audioContext.destination);
  reverb.process(outputSource);
  
  console.log('Output song generated successfully!');
}

function onAudioLoadError() {
  console.error('Error loading audio file!');
}

function setup() {
  createCanvas(400, 400);
}

this is the error I get: p5.sound.min.js:2 Uncaught Error: error connecting to node: [object GainNode] InvalidAccessError: Failed to execute 'connect' on 'AudioNode': cannot connect to an AudioNode belonging to a different audio context. at AudioBufferSourceNode.t [as connect] (p5.sound.min.js:2:20784) at AudioBufferSourceNode.t [as connect] (p5.sound.min.js:2:20680) at p5.onAudioLoaded (119a770a-9f38-49e8-befa-b7046f10e9d7:87:14) at p5.sound.min.js:2:198861 at AudioContext. (p5.sound.min.js:2:102726)

I don't know if this is the correct way of doing that. I appreciate any suggestion on how to solve the problem or better ways to apply effects from p5.js sound library.

i have already installed all the necessary library.

thanks you very much for helping!

0 Answers0