Parcourir la source

Extract all the fancy QT audio functions

Zachary Kotlarek il y a 13 ans
Parent
commit
14e484792d
2 fichiers modifiés avec 88 ajouts et 153 suppressions
  1. 74 52
      dmx/Audio.pm
  2. 14 101
      dmx/rave.pl

+ 74 - 52
dmx/Audio.pm

@@ -5,7 +5,7 @@ use POSIX;
 use File::Touch;
 use File::Basename;
 use Time::HiRes qw( usleep sleep time );
-use IPC::System::Simple qw( system capture );
+use IPC::System::Simple;
 
 # Package name
 package Audio;
@@ -20,16 +20,13 @@ if ($ENV{'DEBUG'}) {
 	$DEBUG = 1;
 }
 
-# Always load the SILENCE file (also serves as a sanity check)
-audioLoad('SILENCE', 'DMX/Silence.wav');
-
 sub runApplescript($) {
 	my ($script) = @_;
 	if ($DEBUG) {
 		print STDERR 'AppleScript: ' . $script . "\n";
 	}
 
-	my $retval = capture('osascript', '-e', $script);
+	my $retval = IPC::System::Simple::capture('osascript', '-e', $script);
 	if ($DEBUG) {
 		print STDERR "\tAppleScript result: " . $retval . "\n";
 	}
@@ -37,10 +34,10 @@ sub runApplescript($) {
 	return $retval;
 }
 
-sub audioAdd($$) {
+sub add($$) {
 	my ($name, $path) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::audioAdd(): ' . $name . "\n";
+		print STDERR 'Audio::add(): ' . $name . "\n";
 	}
 
 	# Construct an absolute file path
@@ -54,47 +51,47 @@ sub audioAdd($$) {
 	}
 
 	# We only support one document per name
-	audioDrop($name);
+	drop($name);
 
 	# Append the array
 	my %tmp = ('path' => $path);
 	$FILES{$name} = \%tmp;
 }
 
-sub audioDrop($) {
+sub drop($) {
 	my ($name) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::dropAudio(): ' . $name . "\n";
+		print STDERR 'Audio::drop(): ' . $name . "\n";
 	}
 
 	# Unload as necessary
-	if (audioLoaded($name)) {
-		audioStop($name);
-		audioUnload($name);
+	if (loaded($name)) {
+		stop($name);
+		unload($name);
 	}
 
 	# Drop as necessary
-	if (audioExists($name)) {
+	if (available($name)) {
 		delete($FILES{$name});
 	}
 }
 
-sub audioLoaded($) {
+sub loaded($) {
 	my ($name) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::audioLoaded(): ' . $name . "\n";
+		print STDERR 'Audio::loaded(): ' . $name . "\n";
 	}
 
-	if (audioExists($name) && defined($FILES{$name}->{'name'})) {
+	if (available($name) && defined($FILES{$name}->{'name'})) {
 		return 1;
 	}
 	return 0;
 }
 
-sub audioExists($) {
+sub available($) {
 	my ($name) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::audioExists(): ' . $name . "\n";
+		print STDERR 'Audio::available(): ' . $name . "\n";
 	}
 
 	if (defined($name) && defined($FILES{$name})) {
@@ -103,30 +100,30 @@ sub audioExists($) {
 	return 0;
 }
 
-sub audioPlay($) {
+sub play($) {
 	my ($name) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::playAudio(): ' . $name . "\n";
+		print STDERR 'Audio::play(): ' . $name . "\n";
 	}
 
 	# Start playback
-	audioBackground($name);
+	background($name);
 
 	# Wait for it to complete
 	my @cmd = ('tell application "QuickTime Player"');
 	push(@cmd, 'repeat while playing of document ' . $FILES{$name}->{'name'} . ' = true');
-	push(@cmd, 'delay 0.05');
+	push(@cmd, 'delay 0.1');
 	push(@cmd, 'end repeat');
 	push(@cmd, 'end tell');
 	runApplescript(join("\n", @cmd));
 }
 
-sub audioBackground($) {
+sub background($) {
 	my ($name) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::playAudio(): ' . $name . "\n";
+		print STDERR 'Audio::background(): ' . $name . "\n";
 	}
-	if (!audioLoaded($name)) {
+	if (!loaded($name)) {
 		die('Invalid QT document: ' . $name . "\n");
 	}
 
@@ -138,12 +135,12 @@ sub audioBackground($) {
 	runApplescript(join("\n", @cmd));
 }
 
-sub audioPlaying($) {
+sub playing($) {
 	my ($name) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::audioPlaying(): ' . $name . "\n";
+		print STDERR 'Audio::playing(): ' . $name . "\n";
 	}
-	if (!audioLoaded($name)) {
+	if (!loaded($name)) {
 		die('Invalid QT document: ' . $name . "\n");
 	}
 
@@ -155,12 +152,12 @@ sub audioPlaying($) {
 	return 0;
 }
 
-sub audioPosition($$) {
+sub position($$) {
 	my ($name, $new) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::audioPosition(): ' . $name . "\n";
+		print STDERR 'Audio::position(): ' . $name . "\n";
 	}
-	if (!audioLoaded($name)) {
+	if (!loaded($name)) {
 		die('Invalid QT document: ' . $name . "\n");
 	}
 
@@ -173,12 +170,12 @@ sub audioPosition($$) {
 	return runApplescript('tell application "QuickTime Player" to get current time of document ' . $FILES{$name}->{'name'});
 }
 
-sub audioRate($$) {
+sub rate($$) {
 	my ($name, $new) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::audioRate(): ' . $name . "\n";
+		print STDERR 'Audio::rate(): ' . $name . "\n";
 	}
-	if (!audioLoaded($name)) {
+	if (!loaded($name)) {
 		die('Invalid QT document: ' . $name . "\n");
 	}
 
@@ -191,15 +188,15 @@ sub audioRate($$) {
 	return runApplescript('tell application "QuickTime Player" to get rate of document ' . $FILES{$name}->{'name'});
 }
 
-sub audioStop($) {
+sub stop($) {
 	my ($name) = @_;
 	if ($DEBUG) {
-		print STDERR "AppleScript::stopAudio()\n";
+		print STDERR "Audio::stopAudio()\n";
 	}
 
 	# Allow control of all documents or a specific document
 	my $doc = 'every document';
-	if (!audioLoaded($name)) {
+	if (!loaded($name)) {
 		$doc = 'document ' . $FILES{$name}->{'name'};
 	}
 
@@ -211,48 +208,51 @@ sub audioStop($) {
 	runApplescript('tell application "Plex" to activate');
 }
 
-sub audioUnload($) {
+sub unload($) {
 	my ($name) = @_;
 	if ($DEBUG) {
-		print STDERR 'AppleScript::loadAudio(): ' . $name . "\n";
+		print STDERR 'Audio::loadAudio(): ' . $name . "\n";
 	}
-	if (!audioExists($name)) {
+	if (!available($name)) {
 		die('Invalid QT document: ' . $name . "\n");
 	}
 
 	# Nothing to do if the file isn't loaded
-	if (!audioLoaded($name)) {
+	if (!loaded($name)) {
 		return;
 	}
 
 	# Close to document
 	runApplescript('tell application "QuickTime Player" to close document ' . $FILES{$name}->{'name'});
+
+	# Delete our local handle
+	delete($FILES{$name}->{'name'});
 }
 
-sub audioLoad($) {
+sub load($) {
 	my ($name) = @_;
-	if (!audioExists($name)) {
-		die('Invalid QT document: ' . $name . "\n");
-	}
 	if ($DEBUG) {
-		print STDERR 'AppleScript::loadAudio(): ' . $name . "\n";
+		print STDERR 'Audio::loadAudio(): ' . $name . "\n";
+	}
+	if (!available($name)) {
+		die('Invalid QT document: ' . $name . "\n");
 	}
 
 	# Unload first, if we're already loaded
-	if (audioLoaded($name)) {
-		audioUnload($name);
+	if (loaded($name)) {
+		unload($name);
 	}
 
 	# Find out how many files are already open
 	my $count = runApplescript('tell application "QuickTime Player" to count items of every document');
 
 	# Open the file
-	system('open', '-a', 'QuickTime Player', $file);
+	IPC::System::Simple::system('open', '-a', 'QuickTime Player', $FILES{$name}->{'path'});
 
 	# Wait for QT to load the new file
 	my @cmd = ('tell application "QuickTime Player"');
 	push(@cmd, 'repeat while (count items of every document) <= ' . $count);
-	push(@cmd, 'delay 0.05');
+	push(@cmd, 'delay 0.1');
 	push(@cmd, 'end repeat');
 	push(@cmd, 'get document 1');
 	push(@cmd, 'end tell');
@@ -263,7 +263,29 @@ sub audioLoad($) {
 	$doc =~ s/\s+$//;
 	$doc =~ s/\"/\\\"/g;
 	$doc = '"' . $doc . '"';
-	return $doc;
+
+	# Save the document handle
+	$FILES{$name}->{'name'} = $doc;
+
+	# Bring Plex back to the front
+	runApplescript('tell application "Plex" to activate');
+}
+
+sub init() {
+	if ($DEBUG) {
+		print STDERR "Audio::init()\n";
+	}
+
+	# Close all QT documents and relaunch QT Player
+	runApplescript('tell application "QuickTime Player" to close every document');
+	runApplescript('tell application "QuickTime Player" to quit');
+	sleep(1);
+	IPC::System::Simple::system('open', '-a', 'QuickTime Player');
+
+	# Always load and play the SILENCE file (for sanity and general init)
+	add('SILENCE', 'DMX/Silence.wav');
+	load('SILENCE');
+	play('SILENCE');
 }
 
 # Always return true

+ 14 - 101
dmx/rave.pl

@@ -12,6 +12,7 @@ use Cwd qw(abs_path);
 use File::Basename qw(dirname);
 use lib dirname(abs_path($0));
 use DMX;
+use Audio;
 
 # Effect Prototypes
 sub red_alert($$$);
@@ -27,15 +28,11 @@ my %EFFECTS    = (
 	'LSR'       => { 'cmd' => \&lsr_init, 'next' => \&lsr_run, 'loop' => \&lsr_loop },
 );
 my %FILES = (
-	'SILENCE'   => { 'file' => 'Silence.wav' },
-	'RED_ALERT' => { 'file' => 'Red Alert.mp3' },
-	'LSR'       => { 'file' => 'Rave.mp3' },
+	'RED_ALERT' => 'DMX/Red Alert.mp3',
+	'LSR'       => 'DMX/Rave.mp3',
 );
 
 # Utility prototypes
-sub openQT($);
-sub playAudio($);
-sub stopAudio();
 sub ampWait($$$);
 
 # App config
@@ -56,6 +53,13 @@ if ($ENV{'DEBUG'}) {
 	$DEBUG = 1;
 }
 
+# Load all our audio files
+Audio::init();
+foreach my $file (keys(%FILES)) {
+	Audio::add($file, $FILES{$file});
+	Audio::load($file);
+}
+
 # Sockets
 DMX::stateSocket($STATE_SOCK);
 DMX::stateSubscribe($STATE_SOCK);
@@ -77,9 +81,6 @@ if (-e $EFFECT_FILE) {
 	unlink($EFFECT_FILE);
 }
 
-# Load all our audio files
-openQT(\%FILES);
-
 # Loop forever
 while (1) {
 
@@ -121,7 +122,7 @@ while (1) {
 			if ($DEBUG) {
 				print STDERR "Ending background processing\n";
 			}
-			stopAudio();
+			Audio::stop(undef());
 			kill(SIGTERM, $PID);
 		}
 
@@ -208,94 +209,6 @@ sub runApplescript($) {
 	return $retval;
 }
 
-sub playAudio($) {
-	my ($name) = @_;
-	if (!defined($name)) {
-		$name = 'SILENCE';
-	}
-	if (!defined($FILES{$name}) || !defined($FILES{$name}->{'name'})) {
-		die('Invalid QT document: ' . $name . "\n");
-	}
-	if ($DEBUG) {
-		print STDERR 'Playing QT document: ' . $FILES{$name}->{'name'} . "\n";
-	}
-
-	my @cmd = ('tell application "QuickTime Player"');
-	push(@cmd, 'set current time of document ' . $FILES{$name}->{'name'} . ' to 0');
-	push(@cmd, 'play document ' . $FILES{$name}->{'name'});
-	push(@cmd, 'repeat while playing of document ' . $FILES{$name}->{'name'} . ' = true');
-	push(@cmd, 'delay 0.05');
-	push(@cmd, 'end repeat');
-	push(@cmd, 'end tell');
-
-	runApplescript(join("\n", @cmd));
-}
-
-sub stopAudio() {
-	if ($DEBUG) {
-		print STDERR "Stopping QT audio\n";
-	}
-
-	# Stop and rewind all QT documents
-	runApplescript('tell application "QuickTime Player" to stop every document');
-	runApplescript('tell application "QuickTime Player" to set current time of every document to 0');
-
-	# Bring Plex back to the front
-	runApplescript('tell application "Plex" to activate');
-}
-
-sub openQT($) {
-	my ($files) = @_;
-
-	# Open QT Player and close all documents, so we know what we're getting
-	system('open', '-a', 'QuickTime Player');
-	runApplescript('tell application "QuickTime Player" to close every document');
-
-	# Keep track of our document numbers
-	my $docIndex = 0;
-
-	# Load all the audio files
-	foreach my $key (keys(%{$files})) {
-		if ($DEBUG) {
-			print STDERR 'Loading QT document: ' . $key . "\n";
-		}
-
-		# Increment the index
-		$docIndex++;
-
-		# Record the document number
-		$files->{$key}->{'index'} = $docIndex;
-
-		# Construct a relative or absolute file path
-		my $file = $files->{$key}->{'file'};
-		if (!($file =~ /^\//)) {
-			$file = $MEDIA_PATH . '/' . $file;
-		}
-
-		# Open the file
-		system('open', '-a', 'QuickTime Player', $file);
-
-		# Wait for QT to load the new file (it's always document 1 -- we just brought it forward)
-		my @cmd = ('tell application "QuickTime Player"');
-		push(@cmd, 'repeat while (count items of every document) < ' . $docIndex);
-		push(@cmd, 'delay 0.05');
-		push(@cmd, 'end repeat');
-		push(@cmd, 'get document 1');
-		push(@cmd, 'end tell');
-		my $doc = runApplescript(join("\n", @cmd));
-
-		# Clean up and store the document name for later use
-		$doc =~ s/^\s*document //;
-		$doc =~ s/\s+$//;
-		$doc =~ s/\"/\\\"/g;
-		$doc = '"' . $doc . '"';
-		$files->{$key}->{'name'} = $doc;
-	}
-
-	# Bring Plex back to the front
-	runApplescript('tell application "Plex" to activate');
-}
-
 sub ampWait($$$) {
 	my ($name, $exists, $params) = @_;
 	if ($DEBUG) {
@@ -369,7 +282,7 @@ sub red_alert($$$) {
 	# Three blasts
 	for (my $i = 0 ; $i < 3 ; $i++) {
 		DMX::dim(\%high);
-		playAudio($name);
+		Audio::play($name);
 		DMX::dim(\%low);
 		usleep($sleep * 1000);
 	}
@@ -421,12 +334,12 @@ sub lsr_run($$$) {
 	}
 
 	# Play a short burst of silence to get all the audio devices in-sync
-	playAudio(undef());
+	Audio::play('SILENCE');
 
 	# Play the sound in a child (i.e. in the background)
 	$PID = fork();
 	if (defined($PID) && $PID == 0) {
-		playAudio($name);
+		Audio::play($name);
 		exit(0);
 	}