Maintain same length of note file .wav while pushing up the octave from 1A to 7G#

184 Views Asked by At

I have this nice code in python, that takes file in 1A.wav , and makes 83 note files from 1A to 7G#. 1A is the lowest note Every note file, gets converted to .ogg 48000hz with 80kbps and mono instead of stereo for further use. The problem is that, every next note file, gets less lengthy. For example, if original came in 20 seconds,then by 7G#, the note file might not even be a second long. I need to make sure every file that gets generated stay's the same length as original 1A.wav.

here's the code

#!/usr/bin/env python

from pydub import AudioSegment
from pydub.playback import play
import wave, struct, math, random
import os

# sound = AudioSegment.from_file('in.wav', format="wav")

list_of_values = ["1A", "1A#", "1B","1C","1C#","1D","1D#","1E","1F","1F#","1G","1G#","2A","2A#","2B","2C","2C#","2D","2D#","2E","2F","2F#","2G","2G#","3A","3A#","3B","3C","3C#","3D","3D#",
"3E","3F","3F#","3G","3G#","4A","4A#","4B","4C","4C#","4D","4D#","4E","4F","4F#","4G","4G#","5A","5A#","5B","5C","5C#","5D","5D#","5E","5F","5F#","5G","5G#","6A","6A#","6B","6C","6C#","6D",
"6D#","6E","6F","6F#","6G","6G#","7A","7A#","7C","7C#","7D","7D#","7E","7F","7F#","7G","7G#"] 





for prev, current, nxt in zip(list_of_values, list_of_values[1:], list_of_values[2:]):
    print(prev, current, nxt)
    
    
    sound = AudioSegment.from_file(prev + '.wav', format="wav")
    octaves = 0.04
    new_sample_rate = int(sound.frame_rate * (2.0 ** octaves))
    hipitch_sound = sound._spawn(sound.raw_data, overrides={'frame_rate': new_sample_rate})
    hipitch_sound = hipitch_sound.set_frame_rate(44100)
    # play(hipitch_sound)
    hipitch_sound.export(current + ".wav", format="wav")


sound = AudioSegment.from_file('7G.wav', format="wav")
octaves = 0.03
new_sample_rate = int(sound.frame_rate * (2.0 ** octaves))
hipitch_sound = sound._spawn(sound.raw_data, overrides={'frame_rate': new_sample_rate})
hipitch_sound = hipitch_sound.set_frame_rate(44100)
#play(hipitch_sound)
hipitch_sound.export("7G#.wav", format="wav")



path = './7G#.wav'

check_file = os.path.isfile(path)
#converts all files to .ogg with 48000hz 80kbps mono and deletes .wav files after
if check_file:
    os.system('for i in *.wav; do ffmpeg -i "$i" -ar 48000 -b:a 80k -ac 1 "${i%.*}.ogg"; done')
    os.system('rm *.wav')

Anyway, I have alternative script called generate_missing_keys.py that might do something like this, but I don't understand how to use it, somebody might understand it?

#!/usr/bin/env python

# source waveforms used:
# https://archive.org/download/SalamanderGrandPianoV3
# file: SalamanderGrandPianoV3_OggVorbis.tar.bz2
# Audio files belong to: Alexander Holm
# Wavforms (input and output) follows license CC BY 3.0
# License of this code: MIT License


# This script generates the missing keys
# (only 4 are provided per octave, others have to be generated)

import os
import subprocess
import shlex

VEL = 7
SRC = 'ogg'
DST = 'piano'


def shell(cmd):
    print('CMD:', cmd)
    subprocess.check_call(shlex.split(cmd.strip()))


def getResKeyRemap():
    keys  = 'C C# D D# E F F# G G# A A# B'.split()
    allowed = 'C D# F# A'.split()
    octmin = 1
    octmax = 7
    okseq  = [ (oc, k) for oc in range(octmin, octmax+1) for k in keys ]
    resmap = {}
    for idx, (oc, k) in enumerate(okseq):
        if k not in allowed:
            continue
        prv = None
        nxt = None
        if idx > 0:
            prv = okseq[idx-1]
        if idx < len(okseq) - 1:
            nxt = okseq[idx+1]
        resmap[(oc, k)] = ((-1, prv), (1, nxt))
    return resmap


def writeMappedTone(base, mapped, shift=0):
    jump = ''
    if shift != 0:
        jump = f'pitch {100*shift:+d}'
    o1, k1 = base
    o2, k2 = mapped
    shell(f'''
           sox {SRC}/{k1}{o1}v{VEL}.ogg
               -r48k -c1
               {DST}/{o2}{k2}.ogg {jump}
           ''')


def processAllKeys(resmap):
    for key, val in resmap.items():
        print('--' * 40)
        writeMappedTone(key, key)
        for shift, mapped in val:
            if mapped is None:
                continue
            writeMappedTone(key, mapped, shift)



def resampleWavs():
    resmap = getResKeyRemap()
    processAllKeys(resmap)


def main():
    resampleWavs()


if __name__ == '__main__':
    main()

after some time of thinking I came up with these:

here's what should be done, since stretching the pitched file would make the note lower again, what I need to be done is to ether cut the higher note in fraction of lost length and add it to end of the higher note.. since sample could be unusual and not just straight sound, this would cause crippling of the sample...

so technically I should do is take the fourier transform and double the frequency there, then back to time domain to get the wave

if anybody knows how to do it in code, please help with some code sample!!

0

There are 0 best solutions below