From 37865943da35f265ab7a805f0f345e577db17de0 Mon Sep 17 00:00:00 2001
From: Dan Donovan <dansolo@none>
Date: Wed, 17 Jan 2007 05:06:17 +0000
Subject: [PATCH] Save PCM .wav clips of lines (right click on line -> Create
 audio clip)

Originally committed to SVN as r816.
---
 aegisub/audio_karaoke.cpp |  4 +--
 aegisub/subs_grid.cpp     | 66 +++++++++++++++++++++++++++++++++++++++
 aegisub/subs_grid.h       | 10 ++++--
 3 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/aegisub/audio_karaoke.cpp b/aegisub/audio_karaoke.cpp
index 254d61c96..beaccb639 100644
--- a/aegisub/audio_karaoke.cpp
+++ b/aegisub/audio_karaoke.cpp
@@ -443,11 +443,11 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
 			Refresh(false);
 		}
 		// Released left button
-		else if (event.LeftUp()) {
+		else if (0&&event.LeftUp()) {
 			ReleaseMouse();
 		}
 		// Released right button; make a menu for selecting \k type
-		else if (event.RightUp()) {
+		else if (0&&event.RightUp()) {
 			ReleaseMouse();
 
 			AudioKaraokeTagMenu menu(this);
diff --git a/aegisub/subs_grid.cpp b/aegisub/subs_grid.cpp
index b711947a7..86dd88e27 100644
--- a/aegisub/subs_grid.cpp
+++ b/aegisub/subs_grid.cpp
@@ -81,6 +81,7 @@ BEGIN_EVENT_TABLE(SubtitlesGrid, BaseGrid)
 	EVT_MENU(MENU_JOIN_AS_KARAOKE,SubtitlesGrid::OnJoinAsKaraoke)
 	EVT_MENU(MENU_SPLIT_BY_KARAOKE,SubtitlesGrid::OnSplitByKaraoke)
 	EVT_MENU(MENU_RECOMBINE,SubtitlesGrid::OnRecombine)
+	EVT_MENU(MENU_AUDIOCLIP,SubtitlesGrid::OnAudioClip)
 	EVT_MENU_RANGE(MENU_SHOW_COL,MENU_SHOW_COL+15,SubtitlesGrid::OnShowColMenu)
 END_EVENT_TABLE()
 
@@ -185,6 +186,12 @@ void SubtitlesGrid::OnPopupMenu(bool alternate) {
 		menu.Append(MENU_RECOMBINE,_("Recombine Lines"),_T("Recombine subtitles when they have been split and merged"))->Enable(state);
 		menu.AppendSeparator();
 
+		//Make audio clip
+		state = sels==1&& parentFrame->audioBox->audioDisplay->loaded==true;
+		menu.Append(MENU_AUDIOCLIP,_("Create audio clip"),_T("Create an audio clip of the selected line"))->Enable(state);
+		menu.AppendSeparator();
+
+
 		// Copy/cut/paste
 		menu.Append(MENU_COPY,_("&Copy"),_T("Copies selected lines to clipboard"));
 		menu.Append(MENU_CUT,_("C&ut"),_T("Cuts selected lines to clipboard"));
@@ -630,6 +637,65 @@ void SubtitlesGrid::OnRecombine(wxCommandEvent &event) {
 }
 
 
+
+//////////////
+// Export audio clip of line
+void SubtitlesGrid::OnAudioClip(wxCommandEvent &event) {
+	AudioDisplay *audioDisplay = parentFrame->audioBox->audioDisplay;
+	AudioProvider *provider = audioDisplay->provider;
+	AssDialogue *cur = GetDialogue(GetFirstSelRow());
+
+	__int64 num_samples = provider->GetNumSamples();
+	__int64 start = audioDisplay->GetSampleAtMS(cur->StartMS);
+	__int64 end = audioDisplay->GetSampleAtMS(cur->End.GetMS());
+	end=(end>=num_samples+1)?num_samples:end;
+	wxString filename = wxFileSelector(_("Save audio clip"),0,0,_T("wav"),0,wxSAVE|wxOVERWRITE_PROMPT,this);
+
+	if (!filename.empty()) {
+		std::ofstream outfile(filename,std::ios::binary);
+		
+		size_t bufsize=(end-start)*provider->GetChannels()*provider->GetBytesPerSample();
+		int intval;
+		short shortval;
+
+		outfile << "RIFF";
+		outfile.write((char*)&(intval=bufsize+36),4);
+		outfile<< "WAVEfmt ";
+		outfile.write((char*)&(intval=16),4);
+		outfile.write((char*)&(shortval=1),2);
+		outfile.write((char*)&(shortval=provider->GetChannels()),2);
+		outfile.write((char*)&(intval=provider->GetSampleRate()),4);
+		outfile.write((char*)&(intval=provider->GetSampleRate()*provider->GetChannels()*provider->GetBytesPerSample()),4);
+		outfile.write((char*)&(intval=provider->GetChannels()*provider->GetBytesPerSample()),2);
+		outfile.write((char*)&(shortval=provider->GetBytesPerSample()<<3),2);
+		outfile << "data";
+		outfile.write((char*)&bufsize,4);
+
+		//samples per read
+		size_t spr = 65536/(provider->GetBytesPerSample()*provider->GetChannels());
+		for(int i=start;i<end;i+=spr) {
+			int len=(i+spr>end)?(end-i):spr;
+			size_t thisbufsize=len*(provider->GetBytesPerSample()*provider->GetChannels());
+			void *buf = malloc(thisbufsize);
+			if (buf) {
+				provider->GetAudio(buf,i,len);
+				outfile.write((char*)buf,thisbufsize);
+				free(buf);
+			}
+			else if (spr>128) {
+				//maybe we can allocate a smaller amount of memory
+				i-=spr; //effectively redo this loop again
+				spr=128;
+			}
+			else {
+				wxMessageBox(_("Couldn't allocate memory."),_("Error"),wxICON_ERROR | wxOK);
+				break;
+			}
+		}
+		
+		outfile.close();
+	}
+}
 //////////////////////////////////////
 // Clears grid and sets it to default
 void SubtitlesGrid::LoadDefault (AssFile *_ass) {
diff --git a/aegisub/subs_grid.h b/aegisub/subs_grid.h
index 1fb1b8fec..619cd7a95 100644
--- a/aegisub/subs_grid.h
+++ b/aegisub/subs_grid.h
@@ -44,7 +44,11 @@
 #include <vector>
 #include <list>
 #include "base_grid.h"
-
+#include "audio_display.h"
+#include "audio_provider.h"
+#include "audio_box.h"
+#include <iostream>
+#include <fstream>
 
 //////////////
 // Prototypes
@@ -93,6 +97,7 @@ private:
 	void OnJoinAsKaraoke(wxCommandEvent &event);
 	void OnSplitByKaraoke(wxCommandEvent &event);
 	void OnRecombine(wxCommandEvent &event);
+	void OnAudioClip(wxCommandEvent &event);
 	void OnShowColMenu(wxCommandEvent &event);
 
 public:
@@ -159,5 +164,6 @@ enum {
 	MENU_SET_VIDEO_TO_START,
 	MENU_SET_VIDEO_TO_END,
 	MENU_GRID_END,
-	MENU_SHOW_COL = 1250
+	MENU_SHOW_COL = 1250,
+	MENU_AUDIOCLIP
 };