diff --git a/aegisub/src/audio_controller.cpp b/aegisub/src/audio_controller.cpp index 5cde9b785..44e7a8099 100644 --- a/aegisub/src/audio_controller.cpp +++ b/aegisub/src/audio_controller.cpp @@ -43,6 +43,8 @@ #include #endif +#include + #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 buf(bufsize); + for(int64_t i = range.begin(); i < range.end(); i += spr) { + size_t len = std::min(spr, range.end() - i); + provider->GetAudio(&buf[0], i, len); + out.write(&buf[0], len * bytes_per_sample); + } +} diff --git a/aegisub/src/audio_controller.h b/aegisub/src/audio_controller.h index aa016347e..cb9ca225c 100644 --- a/aegisub/src/audio_controller.h +++ b/aegisub/src/audio_controller.h @@ -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) diff --git a/aegisub/src/command/audio.cpp b/aegisub/src/command/audio.cpp index ac83ec4a0..b2d2b4672 100644 --- a/aegisub/src/command/audio.cpp +++ b/aegisub/src/command/audio.cpp @@ -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::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 diff --git a/aegisub/src/subs_grid.cpp b/aegisub/src/subs_grid.cpp index 469580db0..889442c8c 100644 --- a/aegisub/src/subs_grid.cpp +++ b/aegisub/src/subs_grid.cpp @@ -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||tempSamplesFromMilliseconds(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;iend)?(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