Last active
May 2, 2016 09:34
-
-
Save BrechtDeMan/33c52fb65a3fc522642194bfab48e88e to your computer and use it in GitHub Desktop.
Heuristically check submissions to the AES Student Recording Competition comply with the rules.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: UTF-8 -*- | |
# Copyright 2015 Brecht De Man | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# See <http://www.gnu.org/licenses/> for a copy of the GNU General Public License. | |
# Made for automatic, heuristic checking of rule compliance of submissions to | |
# the AES Student Recording Competitions. | |
# INSTRUCTIONS | |
# Put in a folder (e.g. 'main') which contain folders (e.g. 'main/category 1') which | |
# contain the submission folders (e.g. 'main/category 1/87654_traditionalacoustic') | |
# or zipped submissions (e.g. 'main/category 1/87654_traditionalacoustic.zip'). | |
# Then run script from Terminal or similar. | |
#TODO: more rigorous file name checking (regex) | |
import os # for getting folder contents | |
import zipfile # for unzipping folders | |
import wave # for reading .wav files | |
import re # for counting pages in PDF document | |
# This function is where you set the audio constraints. | |
def check_wav_file(wav_file_path, n_channels): | |
wav_file = wave.open(wav_file_path, 'r') | |
alertstr = '' | |
# check sample rate | |
if wav_file.getframerate() != 48000: | |
alertstr += '\n\t\t\t! Sample rate = '+str(wav_file.getframerate()) | |
# check bit depth | |
if wav_file.getsampwidth()*8 != 24: # note: sample width is in bytes, not bits | |
alertstr += '\n\t\t\t! Bit depth = '+str(wav_file.getsampwidth()) | |
# check number of channels equal to n_channels | |
if wav_file.getnchannels() != n_channels: | |
alertstr += '\n\t\t\t! Number of channels = '+str(wav_file.getnchannels()) | |
# check length of file | |
file_length_in_seconds = wav_file.getnframes()/wav_file.getframerate() | |
if file_length_in_seconds > 300 or file_length_in_seconds < 180: | |
alertstr += '\n\t\t\t! File length = '+seconds2timestr(file_length_in_seconds) | |
return alertstr | |
# Turn number of seconds (int) to '[minutes] min [seconds] s' (string) | |
def seconds2timestr(time_in_seconds): | |
if time_in_seconds is not None: | |
time_in_minutes = int(time_in_seconds/60) | |
remaining_seconds = int(time_in_seconds%60) | |
return str(time_in_minutes) + " min " + str(remaining_seconds) + " s" | |
else: | |
return 'N/A' | |
# Count pages in a PDF document | |
rxcountpages = re.compile(b'/Type\s*/Page([^s]|$)', re.MULTILINE|re.DOTALL) | |
#rxcountpages = re.compile(r"$/Type\s*/Page([/\s]|$)", re.MULTILINE|re.DOTALL) | |
def count_pages(filename): | |
f = open(filename, 'rb') | |
data = f.read() | |
return len(rxcountpages.findall(data)) | |
category_list = os.listdir('.') | |
for category in category_list: | |
# check if folder | |
if os.path.isdir(category): | |
# print category to console | |
print(category+': ') | |
# unzip each zipped file | |
for file in os.listdir(category): | |
if file.endswith(".zip"): | |
zip_ref = zipfile.ZipFile(category+'/'+file, 'r') | |
zip_ref.extractall(category+'/'+file[:-4]) # extract to eponymous folder | |
zip_ref.close() | |
os.remove(category+'/'+file) # remove zip file | |
# go over each folder in here | |
submission_list = os.listdir(category) | |
count_submissions = 0 | |
for submission in submission_list: | |
if os.path.isdir(category+'/'+submission): # check if submission folder is really a folder | |
# count total number of submissions for this category | |
count_submissions += 1 | |
# print name to console | |
print('\t'+submission) | |
# name: warning if deviates from specified format? | |
#TODO | |
# get all files in submission folder | |
file_list = os.listdir(category+'/'+submission) | |
# get wav files | |
wav_files = [s for s in file_list if s.endswith('.wav') and not s.startswith('.')] | |
if len(wav_files) == 1: # stereo mix | |
# check file name convention | |
if not wav_files[0].endswith(('_traditionalacoustic.wav','_traditionalstudio.wav', '_modernstudioelectro.wav', '_soundforvisual.wav')): | |
print('\t\t! WAV file name: '+wav_files[0]) | |
# print any deviations from rules to console | |
alertstr = check_wav_file(category+'/'+submission+'/'+wav_files[0], 2) | |
if len(alertstr)>0: | |
print('\t\t'+wav_files[0]+': '+alertstr) | |
elif len(wav_files) == 6: # 5.1 mix | |
for wav_file in wav_files: | |
# check file name convention | |
if not wav_file.endswith(('_(C).wav','_(R).wav', '_(L).wav', '_(Rs).wav', '_(Ls).wav', '_(LFE).wav', )) or\ | |
not any(s in wav_file for s in ['_traditionalacoustic_','_traditionalstudio_', | |
'_modernstudioelectro_', '_soundforvisual_']): | |
print('\t\t! WAV file name: '+wav_file) | |
# print any deviations from rules to console | |
alertstr = check_wav_file(category+'/'+submission+'/'+wav_file, 1) | |
if len(alertstr)>0: | |
print('\t\t'+wav_file+': '+alertstr) | |
else: # anything other than 1 or 6 files | |
print('\t\t! Weird number of .WAV files: '+str(len(wav_files))+' found: '+', '.join(wav_files)) | |
# get PDF files | |
pdf_files = [s for s in file_list if s.endswith('.pdf') and not s.startswith('.')] | |
if len(pdf_files) == 0: | |
print('\t\t! No PDF files found.') | |
elif len(pdf_files)>1: | |
print('\t\t! More than one PDF file found: '+', '.join(pdf_files)) | |
else: # read PDF and count pages; alert if over 6 | |
# check file name convention | |
if not pdf_files[0].endswith(('_traditionalacoustic.pdf','_traditionalstudio.pdf', '_modernstudioelectro.pdf', '_soundforvisual.pdf')): | |
print('\t\t! PDF file name: '+pdf_files[0]) | |
n_pages = count_pages(category+'/'+submission+'/'+pdf_files[0]) | |
if n_pages>6 or n_pages<1: # too long or error | |
print('\t\t! Number of documentation pages: '+str(n_pages)) | |
# show any other file (except hidden files) | |
other_files = [s for s in file_list if not (s.endswith('.wav') or s.endswith('.pdf') or s.startswith('.'))] | |
for file in other_files: # print to console | |
print('\t\t\t! Extra file: '+file) | |
# show number of submissions for this category | |
print('Number of submissions: '+str(count_submissions)) | |
# info on what is checked | |
print('''Checked: all .wav and .pdf files. | |
Checked: exactly 1 (stereo) or 6 (5.1) .wav files. | |
Checked: all .wav files end in _[categoryname] (plus _(L), _(Rs), _(LFE)... for 5.1). | |
Checked: all audio 48 kHz / 24 bit. | |
Checked: exactly 1 PDF file ending in _[categoryname]. | |
Checked: between 1 and 6 documentation pages.''') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment