Exemple #1
0
def addFx(sound, effects, pad=3000, fade_in=100, fade_out=100):
    # Add padding
    if pad > 0:
        sound += AudioSegment.silent(duration=pad, frame_rate=sound.frame_rate)

    # convert pydub sound to np array
    samples = np.array(sound.get_array_of_samples())
    samples = samples.astype(np.int16)

    chain = AudioEffectsChain()
    for effect, value in effects:
        if effect == "reverb" and value > 0:
            chain.reverb(reverberance=value)
        elif effect == "distortion" and value > 0:
            chain.overdrive(gain=value)
        elif effect == "highpass" and value > 0:
            chain.highpass(value)
        elif effect == "lowpass" and value > 0:
            chain.lowpass(value)
        elif effect == "bass":
            frequency = 100
            gain = value
            if isinstance(value, tuple):
                gain, frequency = value
            print("%s, %s" % (gain, frequency))
            chain.highshelf(gain=gain, frequency=frequency)
        elif effect == "echo":
            echoStr = "echo 0.8 0.9"
            amount = value
            count = 1
            # check if we have echo count indicated
            if isinstance(value, tuple):
                amount, count = value
            for i in range(count):
                # amount between 10 (robot) and 1000 (mountains)
                echoStr += " %s 0.3" % amount
            chain.custom(echoStr)
        elif effect == "tempo" and value != 1.0 and value != 1:
            chain.tempo(factor=value)

    # apply reverb effect
    fx = (chain)
    y = fx(samples)

    # convert it back to an array and create a new sound clip
    newData = array.array(sound.array_type, y)
    newSound = sound._spawn(newData)
    dur = len(newSound)
    newSound = newSound.fade_in(min(fade_in, dur)).fade_out(min(fade_out, dur))
    return newSound
Exemple #2
0
    def __call__(self, wav_file):
        if not Path(wav_file).exists():
            print(wav_file)
            raise IOError

        sr, wav = scipy.io.wavfile.read(wav_file)
        if wav.ndim > 1 and wav.shape[1] > 1:
            logger.error("wav file has two or more channels")
            sys.exit(1)
        if type(wav[0]) is np.int32:
            wav = wav.astype('float32', copy=False) / 2147483648.0
        elif type(wav[0]) is np.int16:
            wav = wav.astype('float32', copy=False) / 32768.0
        elif type(wav[0]) is np.uint8:
            wav = wav.astype('float32', copy=False) / 256.0 - 128.0

        fx = AudioEffectsChain()

        if self.resample:
            if self.sample_rate > sr:
                ratio = int(self.sample_rate / sr)
                fx.upsample(ratio)
            elif self.sample_rate < sr:
                ratio = int(sr / self.sample_rate)
                fx.custom(f"downsample {ratio}")

        if self.tempo:
            tempo_change = np.random.uniform(*self.tempo_range)
            fx.tempo(tempo_change, opt_flag="s")

        if self.pitch:
            pitch_change = np.random.uniform(*self.pitch_range)
            fx.pitch(pitch_change)

        # dithering
        fx.custom(f"dither -s")

        wav = fx(wav, sample_in=sr, sample_out=self.sample_rate)
        #wav = wav / max(abs(wav))

        # normalize audio power
        gain = 0.1
        wav_energy = np.sqrt(np.sum(np.power(wav, 2)) / wav.size)
        wav = gain * wav / wav_energy

        # sample-domain padding
        if self.padding:
            wav = np.pad(wav, self.num_padding, mode='constant')

        # sample-domain offset
        if self.offset:
            offset = np.random.randint(*self.offset_range)
            wav = np.roll(wav, offset, axis=0)

        if self.noise:
            snr = 10.0**(np.random.uniform(*self.noise_range) / 10.0)
            noise = np.random.normal(0, 1, wav.shape)
            noise_energy = np.sqrt(np.sum(np.power(noise, 2)) / noise.size)
            wav = wav + snr * gain * noise / noise_energy

        #filename = wav_file.replace(".wav", "_augmented.wav")
        #scipy.io.wavfile.write(filename, self.sample_rate, wav)
        return torch.FloatTensor(wav)
Exemple #3
0
def main():
    # Parsing for command line arguments
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description=
        ("Creates a vaporwave (slowed, with reverb) remix of a given MP3 file, with"
         " multiple audio effects available, and the option of playing over a looped"
         " GIF as a video."),
    )

    parser.add_argument(
        "-o",
        "--output",
        dest="output_name",
        help=
        ("Name of output file(s), instead of audio file name with the addition of"
         " '_vaporised'."),
        type=str,
    )

    required_arguments = parser.add_argument_group("required arguments")

    required_arguments.add_argument(
        "-a",
        "--audio",
        dest="audio_input",
        help="Input audio file to vaporise (.mp3)",
        type=str,
        required=True,
    )

    audio_arguments = parser.add_argument_group(
        "audio arguments",
        "these arguments control audio effects that will be applied by default",
    )

    audio_arguments.add_argument(
        "-s",
        "--speed",
        dest="speed_ratio",
        help="Ratio of new playback speed to old speed.",
        type=float,
        default=0.75,
    )

    audio_arguments.add_argument(
        "-p",
        "--pitch",
        dest="pitch_shift",
        help="Pitch shift (100ths of a semitone).",
        type=float,
        default=-75,
    )

    audio_arguments.add_argument(
        "-l",
        "--lowpass",
        dest="lowpass_cutoff",
        help="Cutoff for lowpass filter (Hz).",
        type=int,
        default=3500,
    )

    audio_arguments_optional = parser.add_argument_group(
        "extra audio arguments",
        "these arguments control extra, optional audio effects")

    audio_arguments_optional.add_argument(
        "-b",
        "--bass",
        dest="bass_boost",
        help="Add a bass boost effect (e.g. --bass 3).",
        type=int,
        default=None,
    )

    audio_arguments_optional.add_argument(
        "-ga",
        "--gain",
        dest="gain_db",
        help="Applies gain (dB).",
        type=int,
        default=None,
    )

    audio_arguments_optional.add_argument(
        "-op",
        "--oops",
        dest="oops",
        help=
        ("Applies Out Of Phase Stereo effect. This is sometimes known as the"
         " ‘karaoke’ effect as it often has the effect of removing most or all of"
         " the vocals from a recording."),
        action="store_true",
    )

    audio_arguments_optional.add_argument(
        "-ph",
        "--phaser",
        dest="phaser",
        help="Enable phaser effect.",
        action="store_true",
    )

    audio_arguments_optional.add_argument(
        "-tr",
        "--tremolo",
        dest="tremolo",
        help="Enable tremolo effect.",
        action="store_true",
    )

    audio_arguments_optional.add_argument(
        "-co",
        "--compand",
        dest="compand",
        help="Enable compand, which compresses the dynamic range of the audio.",
        action="store_true",
    )

    video_arguments = parser.add_argument_group(
        "video arguments",
        "optional arguments, result in an MP4 video output in addition to the MP3"
        " audio",
    )

    video_arguments.add_argument(
        "-g",
        "--gif",
        dest="gif_file",
        help=
        ("Input GIF file to loop. Without a GIF, only an MP3 is created. With a GIF,"
         " an MP4 video is also created."),
        type=str,
    )

    video_arguments.add_argument(
        "-sb",
        "--sobel",
        dest="sobel_filter",
        help="Applies a Sobel filter to video output.",
        action="store_true",
    )

    args = parser.parse_args()

    # Setting name of output file
    if args.output_name is None:
        # If no output name is given, add "_vaporised" to input audio file name
        audio_input_string = re.sub(".mp3", "", str(args.audio_input))
        audio_output = audio_input_string + "_vaporised.mp3"
        video_output = audio_input_string + "_vaporised.mp4"
    else:
        # Otherwise, use the output file name given via the command line
        output_string = re.sub(".mp3", "", str(args.output_name))
        output_string = re.sub(".mp4", "", str(output_string))
        audio_output = output_string + ".mp3"
        video_output = output_string + ".mp4"
        if args.audio_input == args.output_name:
            print("ERROR: Input and output name are identical")
            sys.exit()

    # Creating an audio effects chain, beginning with...
    if args.bass_boost:
        # ...bass boost effect
        bass_boost = f'{"bass "}{args.bass_boost}'
        fx = AudioEffectsChain().custom(bass_boost)
        fx = fx.pitch(args.pitch_shift)
    else:
        # ...pitch shift
        fx = AudioEffectsChain().pitch(args.pitch_shift)

    # Adding OOPS to audio effects chain
    if args.oops:
        fx = fx.custom("oops")

    # Adding tremolo effect to the audio effects chain
    if args.tremolo:
        fx = fx.tremolo(freq=500, depth=50)

    # Adding phaser to the audio effects chain
    if args.phaser:
        # fx.phaser(gain_in, gain_out, delay, decay, speed)
        fx = fx.phaser(0.9, 0.8, 2, 0.2, 0.5)

    # Adding gain to the audio effects chain
    if args.gain_db is not None:
        fx = fx.gain(db=args.gain_db)

    # Adding compand to the audio effects chain
    if args.compand:
        fx = fx.compand()

    # Adding reverb, lowpass filter, speed alteration to audio effects chain
    fx = fx.speed(args.speed_ratio).lowpass(args.lowpass_cutoff).reverb()

    # Applying audio effects
    fx(args.audio_input, audio_output)

    def apply_sobel(image):
        # returns image with Sobel filter applied
        return sobel(image.astype(float))

    # Create video if a GIF file is provided
    if args.gif_file is None:
        # If no GIF is provided, exit here
        print("Script finished at",
              datetime.datetime.now().strftime("%H:%M:%S"))
        print("Vaporised MP3 file (audio):", audio_output)
        sys.exit()
    else:
        # If a GIF is provided, loop it for the length of the vaporised audio file
        mp3_movedit = movedit.AudioFileClip(audio_output)
        gif_movedit = movedit.VideoFileClip(args.gif_file)
        number_of_loops = float(mp3_movedit.duration / gif_movedit.duration)
        gif_looped = gif_movedit.loop(number_of_loops)
        # Applies Sobel filter to looped GIF, if --sobel is used
        if args.sobel_filter:
            gif_looped = gif_looped.fl_image(apply_sobel)
        gif_looped_with_audio = gif_looped.set_audio(mp3_movedit)
        gif_looped_with_audio.write_videofile(video_output)
        print("Script finished at",
              datetime.datetime.now().strftime("%H:%M:%S"))
        print("Vaporised MP3 file (audio):", audio_output)
        print("Vaporised MP4 file (video):", video_output)