igorski / MWEngine

Audio engine and DSP library for Android, written in C++ providing low latency performance within a musical context, while providing a Java/Kotlin API. Supports both OpenSL and AAudio.
MIT License
257 stars 45 forks source link

Is there way to save the recorded audio file with effect without playing whole song ? 🥺 #155

Closed Magesh-mahi closed 2 years ago

Magesh-mahi commented 2 years ago

Hi @igorski ,

I try to add effect(reverb) to my already recorded voice. which i done by

  1. Create a SampledInstrument and load asset from file,
  2. Then add processor(reverb) to processing chain,
  3. Then play event,
  4. Wait for whole recoding to complete and Write to disk,

The effect added to my voice fine.

What i want to know is, is there any way to save(Write to Disk) the file with Voice and Effect(reverb) with out playing the whole section, using MWEngine?

Hoping for any suggestions, 🥺

igorski commented 2 years ago

Hi @Magesh-mahi

Rendering of a single audio event (in your case the voice would be a SampleEvent instance) is possible as of commit cfa7ddd3871157a90c4e1e4557bf12b28d2d787b using the AudioRenderer class renderEvent-method. You can pass in an event and a ProcessingChain instance (or null) so the effects can also be applied, if desired.

This method can even be invoked while the engine is playing as it will execute in a separate thread.

Java example:

import nl.igorski.mwengine.core.AudioRenderer;

boolean AudioRenderer.renderEvent(
    Environment.getExternalStorageDirectory().getAbsolutePath() + PATH_TO_GENERATED_OUTPUT_FILE,
    AUDIO_EVENT_INSTANCE,
    INSTRUMENT_INSTANCE.getAudioChannel().getProcessingChain()
);

Additionally, you can also render the audio from arbitrary files against a ProcessingChain of choice:

import nl.igorski.mwengine.core.AudioRenderer;

boolean AudioRenderer.renderFile(
    Environment.getExternalStorageDirectory().getAbsolutePath() + PATH_TO_SAMPLE_FILE,
    Environment.getExternalStorageDirectory().getAbsolutePath() + PATH_TO_GENERATED_OUTPUT_FILE,
    INSTRUMENT_INSTANCE.getAudioChannel().getProcessingChain()
);
Magesh-mahi commented 2 years ago

Helo @igorski ,

when i try to use

boolean AudioRenderer.renderFile( Environment.getExternalStorageDirectory().getAbsolutePath() + PATH_TO_SAMPLE_FILE, Environment.getExternalStorageDirectory().getAbsolutePath() + PATH_TO_GENERATED_OUTPUT_FILE, INSTRUMENT_INSTANCE.getAudioChannel().getProcessingChain() ); the following error occurred

  AudioRenderer.renderFile(
                   ^

symbol: method renderFile(String,String,ProcessingChain) location: class AudioRenderer..

Seems the renderFile Method is not Found in AudioRenderer..

Can you take a look in this. and really appreciate your reply. Thank you @igorski

Magesh-mahi commented 2 years ago

Hi @igorski ,

  1. What if i want to multiple audio event( voice and music). i want to add effect to voice and not to the music and want to render both files together.

  2. when i try this.

import nl.igorski.mwengine.core.AudioRenderer;

INSTRUMENT_INSTANCE.getAudioChannel().getProcessingChain().addProcessor(reverbsm);

boolean AudioRenderer.renderEvent( Environment.getExternalStorageDirectory().getAbsolutePath() + PATH_TO_GENERATED_OUTPUT_FILE, AUDIO_EVENT_INSTANCE, INSTRUMENT_INSTANCE.getAudioChannel().getProcessingChain() );

The back ground thread make some squess noise in background for few second( i assume while rendering)

Thank you @igorski 😊

igorski commented 2 years ago

If you can't find renderFile in AudioRenderer and you are sure you have pulled the latest changes and rebuilt the engine (running mwengine:assemble) it might help to invalidate the Android Studio caches (when using AS, I noticed the latest version has some issues with detecting file changes).

If by "background thread making noise" you mean that you are running AudioRenderer renders while the audio engine is playing back audio it might help to double check you are not running these calls in the same thread (for instance calling AudioRenderer.render... from an engine callback). If you cannot easily separate the threads, you can run your AudioRenderer.render.. calls in an runOnUiThread-call (see the example activity doing something similar for writing audio to disk)

Magesh-mahi commented 2 years ago

Hi @igorski ,

First of all thank you for your time and reply 😊.

  1. After clean the caches in android studio now i am able to use the function renderFile()
  2. By stoping the Engine before call the renderFile() stop that noise seems

3. renderFile() allow only one file to render. but i am try to merger 2 files, one with effect and one with out effect and final output want be a single music with voice(and effect in voice). any suggestion 🤔.

Magesh-mahi commented 2 years ago

Hi @igorski ,

Sorry to bother you again, is there any update on merging more than 2 files using renderFile(); or is there any method available to do.

Thank you @igorski 😊

igorski commented 2 years ago

Hi there, in commit 6e460900b446a59cb8dbf7f7d3840f04a6826503 a new utility has been added to AudioRenderer. You can specify the path to two input files and a path to an output file to merge the files. So basically, if you use AudioRenderer.renderFile() to generate an output file with or without effects (by supplying a ProcessingChain instance or null) you can create the blend you want.

AudioRenderer.mergeFiles( String pathInputFile1, String pathInputFile2, String pathMerged OutputFile, boolean attenuate );

Attenuate can be false to mix all audio as-is or true to apply an appropriate mix volume (meaning two files with very loud signals will not lead to clipping).

Magesh-mahi commented 2 years ago

Hi @igorski ,

Thank you so much. saved me lot of time. working great. 😊😊