Skip to content

Instantly share code, notes, and snippets.

@BrechtDeMan
Last active May 2, 2016 09:34
Show Gist options
  • Save BrechtDeMan/33c52fb65a3fc522642194bfab48e88e to your computer and use it in GitHub Desktop.
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.
# -*- 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