forked from mia/Aegisub
Add command and AudioController support for saving audio clips
Originally committed to SVN as r5218.
This commit is contained in:
parent
403d465475
commit
be71a66600
4 changed files with 67 additions and 80 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue