Add command and AudioController support for saving audio clips

Originally committed to SVN as r5218.
This commit is contained in:
Thomas Goyne 2011-01-16 07:18:00 +00:00
parent 403d465475
commit be71a66600
4 changed files with 67 additions and 80 deletions

View file

@ -43,6 +43,8 @@
#include <wx/filename.h>
#endif
#include <libaegisub/io.h>
#include "selection_controller.h"
#include "audio_controller.h"
#include "include/aegisub/audio_provider.h"
@ -475,3 +477,39 @@ int64_t AudioController::MillisecondsFromSamples(int64_t samples) const
return millisamples / sr;
}
void AudioController::SaveClip(wxString const& filename, SampleRange const& range) const
{
if (filename.empty() || range.begin() > provider->GetNumSamples() || range.length() == 0) return;
agi::io::Save outfile(STD_STR(filename), true);
std::ofstream& out(outfile.Get());
size_t bytes_per_sample = provider->GetBytesPerSample() * provider->GetChannels();
size_t bufsize = range.length() * bytes_per_sample;
int intval;
short shortval;
out << "RIFF";
out.write((char*)&(intval=bufsize+36),4);
out<< "WAVEfmt ";
out.write((char*)&(intval=16),4);
out.write((char*)&(shortval=1),2);
out.write((char*)&(shortval=provider->GetChannels()),2);
out.write((char*)&(intval=provider->GetSampleRate()),4);
out.write((char*)&(intval=provider->GetSampleRate()*provider->GetChannels()*provider->GetBytesPerSample()),4);
out.write((char*)&(intval=provider->GetChannels()*provider->GetBytesPerSample()),2);
out.write((char*)&(shortval=provider->GetBytesPerSample()<<3),2);
out << "data";
out.write((char*)&bufsize,4);
//samples per read
size_t spr = 65536 / bytes_per_sample;
std::vector<char> buf(bufsize);
for(int64_t i = range.begin(); i < range.end(); i += spr) {
size_t len = std::min<size_t>(spr, range.end() - i);
provider->GetAudio(&buf[0], i, len);
out.write(&buf[0], len * bytes_per_sample);
}
}

View file

@ -335,6 +335,11 @@ public:
/// @return The index of the first sample that is wholly inside the millisecond
int64_t SamplesFromMilliseconds(int64_t ms) const;
/// @brief Save a portion of the decoded loaded audio to a wav file
/// @param filename File to save to
/// @param range Range of samples to save
void SaveClip(wxString const& filename, SampleRange const& range) const;
DEFINE_SIGNAL_ADDERS(AnnounceAudioOpen, AddAudioOpenListener)
DEFINE_SIGNAL_ADDERS(AnnounceAudioClose, AddAudioCloseListener)
DEFINE_SIGNAL_ADDERS(AnnouncePlaybackPosition, AddPlaybackPositionListener)

View file

@ -44,11 +44,15 @@
#include "command.h"
#include "../ass_dialogue.h"
#include "../audio_controller.h"
#include "../compat.h"
#include "../include/aegisub/context.h"
#include "../selection_controller.h"
#include "../main.h"
typedef SelectionController<AssDialogue>::Selection Selection;
namespace cmd {
/// @defgroup cmd-audio Audio commands.
/// @{
@ -152,6 +156,24 @@ struct audio_view_waveform : public Command {
}
};
/// Save the audio for the selected lines..
struct audio_save_clip : public Command {
CMD_NAME("audio/save/clip")
STR_MENU("Create audio clip")
STR_DISP("Create audio clip")
STR_HELP("Create an audio clip of the selected line")
void operator()(agi::Context *c) {
Selection sel = c->selectionController->GetSelectedSet();
for (Selection::iterator it = sel.begin(); it != sel.end(); ++it) {
c->audioController->SaveClip(
wxFileSelector(_("Save audio clip"), "", "", "wav", "", wxFD_SAVE|wxFD_OVERWRITE_PROMPT, c->parent),
SampleRange(c->audioController->SamplesFromMilliseconds((*it)->Start.GetMS()),
c->audioController->SamplesFromMilliseconds((*it)->End.GetMS())));
}
}
};
/// @}
/// Init audio/ commands
@ -163,6 +185,7 @@ void init_audio(CommandManager *cm) {
cm->reg(new audio_open_video());
cm->reg(new audio_view_spectrum());
cm->reg(new audio_view_waveform());
cm->reg(new audio_save_clip());
}
} // namespace cmd

View file

@ -216,7 +216,7 @@ void SubtitlesGrid::OnPopupMenu(bool alternate) {
//Make audio clip
state = context->audioController->IsAudioOpen();
//append_command(menu, "MENU_AUDIOCLIP", state);
append_command(menu, "audio/save/clip", state);
menu.AppendSeparator();
@ -437,85 +437,6 @@ void SubtitlesGrid::RecombineLines() {
SetActiveLine(activeLine);
}
/// @brief Export audio clip of line
/*void SubtitlesGrid::OnAudioClip(wxCommandEvent &) {
int64_t num_samples,start=0,end=0,temp;
AudioController *audioController = context->audioController;
const AudioProvider *provider = audioController->GetAudioProvider();
AssDialogue *cur;
wxArrayInt sel = GetSelection();
num_samples = provider->GetNumSamples();
for(unsigned int i=0;i!=sel.GetCount();i++) {
cur = GetDialogue(sel[i]);
temp = audioController->SamplesFromMilliseconds(cur->Start.GetMS());
start = (i==0||temp<start)?temp:start;
temp = audioController->SamplesFromMilliseconds(cur->End.GetMS());
end = (i==0||temp>end)?temp:end;
}
if (start > num_samples) {
wxMessageBox(_("The starting point is beyond the length of the audio loaded."),_("Error"));
return;
}
if (start==end||end==0) {
wxMessageBox(_("There is no audio to save."),_("Error"));
return;
}
end=(end>num_samples)?num_samples:end;
wxString filename = wxFileSelector(_("Save audio clip"),_T(""),_T(""),_T("wav"),_T(""),wxFD_SAVE|wxFD_OVERWRITE_PROMPT,this);
if (!filename.empty()) {
std::ofstream outfile(filename.mb_str(csConvLocal),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(int64_t i=start;i<end;i+=spr) {
int len=(i+(int64_t)spr>end)?(end-i):spr;
bufsize=len*(provider->GetBytesPerSample()*provider->GetChannels());
void *buf = malloc(bufsize);
if (buf) {
provider->GetAudio(buf,i,len);
outfile.write((char*)buf,bufsize);
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; // don't return, we need to close the file
}
}
outfile.close();
}
}*/
/// @brief Swaps two lines
/// @param n1
/// @param n2