├── .gitignore ├── requirements.txt ├── README.md └── init.py /.gitignore: -------------------------------------------------------------------------------- 1 | compiled 2 | mp3 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pydub==0.23.0 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ambisonic Audio 2 | 3 | This repo is just a sample. 4 | I need to add more effects and support to convert also video source. 5 | 6 | ## How it works 7 | Thanks to PyDub, the script take an audio source (mono or stereo), split the audio in several parts (each part has a duration of 0.2 sec) then put in overlay the same audio track, but with an inverse phase (I tried to make a good mix). 8 | 9 | Then we can merge the parts in a single audio tracks by panning each part of 5degree angle (this make the 360 effetcs). 10 | 11 | 12 | It's really simple now, but I would like to improve the script with some formula and other sources. 13 | Feel free to contribute. -------------------------------------------------------------------------------- /init.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from glob import glob 4 | from pydub import AudioSegment 5 | from pydub.generators import WhiteNoise 6 | from math import * 7 | from random import * 8 | import argparse 9 | import subprocess 10 | import sys 11 | 12 | parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) 13 | 14 | parser.add_argument('-i', type=str, 15 | metavar='Source audio path', required=True, 16 | help='Path to source file.') 17 | parser.add_argument('-o', type=str, 18 | metavar='Modified audio path', required=True, 19 | help='Path to modified file.') 20 | 21 | args = parser.parse_args() 22 | 23 | if not args.i and not i: 24 | raise Exception('Missing -i Input option') 25 | if not args.o and not o: 26 | raise Exception('Missing -o Output option') 27 | 28 | # if len(sys.argv) > 2: 29 | # AudioSegment.converter = sys.argv[1] #ffmpeg installation exe dir path 30 | # AudioSegment.ffmpeg = sys.argv[1] #ffmpeg installation exe dir path 31 | # AudioSegment.ffprobe = sys.argv[2] #ffprobe installation exe dir path 32 | 33 | def calc_pan(index): 34 | return cos(radians(index)) 35 | 36 | #playlist_songs = [AudioSegment.from_mp3(mp3_file) for mp3_file in glob("mp3/*.mp3")] 37 | 38 | #first_song = playlist_songs.pop(0) 39 | interval = 0.2 * 1000 # sec 40 | song = AudioSegment.from_mp3(args.i) 41 | song_inverted = song.invert_phase() 42 | song.overlay(song_inverted) 43 | 44 | splitted_song = splitted_song_inverted = [] 45 | song_start_point = 0 46 | 47 | print("Splitting track " + args.i + " in parts......") 48 | while song_start_point+interval < len(song): 49 | splitted_song.append(song[song_start_point:song_start_point+interval]) 50 | song_start_point += interval 51 | 52 | if song_start_point < len(song): 53 | splitted_song.append(song[song_start_point:]) 54 | 55 | print("End of splitting......") 56 | print("total pieces: " + str(len(splitted_song))) 57 | 58 | ambisonics_song = splitted_song.pop(0) 59 | pan_index = 0 60 | for piece in splitted_song: 61 | pan_index += 5 62 | piece = piece.pan(calc_pan(pan_index)) 63 | ambisonics_song = ambisonics_song.append(piece, crossfade=interval/50) 64 | 65 | # lets save it! 66 | out_f = open("8d.mp3", 'wb') 67 | 68 | ambisonics_song.export(out_f, format='mp3') 69 | 70 | subprocess.call("ffmpeg -i 8d.mp3 -codec:a libmp3lame -b:a 320k " + args.o, shell=True) 71 | --------------------------------------------------------------------------------