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>
|
#include <wx/filename.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <libaegisub/io.h>
|
||||||
|
|
||||||
#include "selection_controller.h"
|
#include "selection_controller.h"
|
||||||
#include "audio_controller.h"
|
#include "audio_controller.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
@ -475,3 +477,39 @@ int64_t AudioController::MillisecondsFromSamples(int64_t samples) const
|
||||||
|
|
||||||
return millisamples / sr;
|
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
|
/// @return The index of the first sample that is wholly inside the millisecond
|
||||||
int64_t SamplesFromMilliseconds(int64_t ms) const;
|
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(AnnounceAudioOpen, AddAudioOpenListener)
|
||||||
DEFINE_SIGNAL_ADDERS(AnnounceAudioClose, AddAudioCloseListener)
|
DEFINE_SIGNAL_ADDERS(AnnounceAudioClose, AddAudioCloseListener)
|
||||||
DEFINE_SIGNAL_ADDERS(AnnouncePlaybackPosition, AddPlaybackPositionListener)
|
DEFINE_SIGNAL_ADDERS(AnnouncePlaybackPosition, AddPlaybackPositionListener)
|
||||||
|
|
|
@ -44,11 +44,15 @@
|
||||||
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
|
||||||
|
#include "../ass_dialogue.h"
|
||||||
#include "../audio_controller.h"
|
#include "../audio_controller.h"
|
||||||
#include "../compat.h"
|
#include "../compat.h"
|
||||||
#include "../include/aegisub/context.h"
|
#include "../include/aegisub/context.h"
|
||||||
|
#include "../selection_controller.h"
|
||||||
#include "../main.h"
|
#include "../main.h"
|
||||||
|
|
||||||
|
typedef SelectionController<AssDialogue>::Selection Selection;
|
||||||
|
|
||||||
namespace cmd {
|
namespace cmd {
|
||||||
/// @defgroup cmd-audio Audio commands.
|
/// @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
|
/// Init audio/ commands
|
||||||
|
@ -163,6 +185,7 @@ void init_audio(CommandManager *cm) {
|
||||||
cm->reg(new audio_open_video());
|
cm->reg(new audio_open_video());
|
||||||
cm->reg(new audio_view_spectrum());
|
cm->reg(new audio_view_spectrum());
|
||||||
cm->reg(new audio_view_waveform());
|
cm->reg(new audio_view_waveform());
|
||||||
|
cm->reg(new audio_save_clip());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cmd
|
} // namespace cmd
|
||||||
|
|
|
@ -216,7 +216,7 @@ void SubtitlesGrid::OnPopupMenu(bool alternate) {
|
||||||
|
|
||||||
//Make audio clip
|
//Make audio clip
|
||||||
state = context->audioController->IsAudioOpen();
|
state = context->audioController->IsAudioOpen();
|
||||||
//append_command(menu, "MENU_AUDIOCLIP", state);
|
append_command(menu, "audio/save/clip", state);
|
||||||
menu.AppendSeparator();
|
menu.AppendSeparator();
|
||||||
|
|
||||||
|
|
||||||
|
@ -437,85 +437,6 @@ void SubtitlesGrid::RecombineLines() {
|
||||||
SetActiveLine(activeLine);
|
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
|
/// @brief Swaps two lines
|
||||||
/// @param n1
|
/// @param n1
|
||||||
/// @param n2
|
/// @param n2
|
||||||
|
|
Loading…
Reference in a new issue