#!/usr/bin/env python3 """Local Apple AAC audition and clip reports. Requires macOS and Python 3. Usage: python3 apple-master-check.py "exported master.wav" Never uploads audio. Never changes the input. This does not certify a studio. """ import argparse, datetime, hashlib, json, os, pathlib, platform, re, shutil, struct, subprocess, sys, tempfile GUIDE = 'https://www.apple.com/apple-music/apple-digital-masters/docs/apple-digital-masters.pdf' def digest(path): h = hashlib.sha256() with open(path, 'rb') as f: for block in iter(lambda: f.read(1024 * 1024), b''): h.update(block) return h.hexdigest() def pcm_info(path): with open(path, 'rb') as f: head = f.read(12) if head[:4] != b'RIFF' or head[8:] != b'WAVE': raise ValueError('Choose a 24-bit PCM WAV export.') size = os.fstat(f.fileno()).st_size fmt = None; audio_bytes = 0 while f.tell() + 8 <= size: tag, length = struct.unpack('<4sI', f.read(8)) if f.tell() + length > size: raise ValueError('Truncated WAV file.') if tag == b'fmt ': fmt = f.read(min(length, 64)); f.seek(max(0, length - 64), 1) else: if tag == b'data': audio_bytes += length f.seek(length, 1) if length % 2: f.seek(1, 1) if not fmt or len(fmt) < 16: raise ValueError('WAV format information is missing.') kind, channels, rate, byte_rate, align, bits = struct.unpack(' 8 * 1024 * 1024: limit = True; process.kill(); out.write(b'\nReport size limit reached; clipping check incomplete.\n'); break out.write(line) clipped |= b'CLIPPED SAMPLES:' in line clean |= b'-- no samples clipped --' in line code = process.wait() status = 'clipping_detected' if clipped else 'no_clipping_detected' if clean and code == 0 and not limit else 'unverified' return dict(status=status, complete=code == 0 and not limit, exit_code=code, log=log.name) def main(argv=None): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('wav', type=pathlib.Path) parser.add_argument('--output-parent', type=pathlib.Path, help='Existing folder for a new, unique QC package; defaults beside input.') args = parser.parse_args(argv) if platform.system() != 'Darwin': parser.error('Run this helper on a Mac with Apple afconvert and afclip installed.') for tool in ('afconvert', 'afclip'): if not os.access('/usr/bin/' + tool, os.X_OK): parser.error('Apple ' + tool + ' is unavailable. Install Apple mastering tools from apple.com.') try: source = args.wav.expanduser().resolve(strict=True); info = pcm_info(source) parent = (args.output_parent or source.parent).expanduser().resolve(strict=True) except (OSError, ValueError) as e: parser.error(str(e)) folder = pathlib.Path(tempfile.mkdtemp(prefix='ArtistPro-Apple-QC-', dir=parent)) report = dict(version=1, created_utc=datetime.datetime.now(datetime.timezone.utc).isoformat(), source_file=source.name, pcm=info, macos=platform.mac_ver()[0], recipe=GUIDE, apple_studio_approval='unverified', source_history='requires_owner_verification', listening_review='required', certified=False, status='incomplete') print('Preparing local Apple audition package:', folder) try: snapshot = folder / 'delivery-master.wav' original_hash = digest(source); shutil.copyfile(source, snapshot) if original_hash != digest(snapshot) or original_hash != digest(source): raise RuntimeError('Source changed during copy. Run again with a stable export.') report['delivery_sha256'] = original_hash report['pcm_clipping'] = clips(snapshot, folder, 'pcm') final_rate = 44100 if info['sample_rate'] in (44100, 88200) else 48000 intermediate = folder / 'intermediate.caf'; aac = folder / 'apple-audition.m4a'; decoded = folder / 'aac-decoded-audition.wav' conversion = ['-d', '0'] if info['sample_rate'] == final_rate else ['-d', 'LEF32@' + str(final_rate), '--src-complexity', 'bats', '-r', '127'] run(['/usr/bin/afconvert', str(snapshot), str(intermediate), *conversion, '-f', 'caff', '--soundcheck-generate'], folder, 'prepare.txt') run(['/usr/bin/afconvert', str(intermediate), str(aac), '-d', 'aac', '-f', 'm4af', '-u', 'pgcm', '2', '--soundcheck-read', '-b', '256000', '-q', '127', '-s', '2'], folder, 'encode.txt') report['aac_clipping'] = clips(aac, folder, 'aac') run(['/usr/bin/afconvert', str(aac), str(decoded), '-d', 'LEI24', '-f', 'WAVE'], folder, 'decode.txt') report['audition'] = dict(file=aac.name, sha256=digest(aac), sample_rate=final_rate, target_bitrate=256000, decoded_file=decoded.name) report['status'] = 'listening_review_required' if all(report[k]['status'] == 'no_clipping_detected' for k in ('pcm_clipping', 'aac_clipping')) else 'technical_review_required' except Exception as e: report['error'] = str(e) finally: (folder / 'report.json').write_text(json.dumps(report, indent=2) + '\n') (folder / 'READ-ME.txt').write_text('Apple audition package\n\nDeliver delivery-master.wav, the unchanged native-rate PCM master.\nThe M4A and decoded WAV are for listening comparisons only.\nRead report.json and both afclip logs. Unverified or incomplete checks do not pass.\nListen to the entire Apple AAC encode against the original. Adjust and rerun if needed.\nConfirm native source history, credits, studio approval and distributor acceptance separately.\nNo Apple approval or certification is claimed by this package.\n\n' + GUIDE + '\n') print('Result:', report['status'], '— see report.json. Apple approval and listening review remain separate.') return 0 if report['status'] == 'listening_review_required' else 2 if __name__ == '__main__': sys.exit(main())