ogg/flac support bits and pieces; fix up MIDI note dragging and front-edge trims; BROKEN IN PERCUSSIVE MODE FOR NOW
git-svn-id: svn://localhost/ardour2/branches/3.0@5745 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
77364b0e25
commit
aefcce1c99
@ -52,7 +52,8 @@ public:
|
||||
void set_outline_color(uint32_t c) { property_outline_color_rgba() = c; }
|
||||
void set_fill_color(uint32_t c) { property_fill_color_rgba() = c; }
|
||||
|
||||
bool on_event(GdkEvent* ev) { return CanvasNoteEvent::on_event(ev); }
|
||||
bool on_event(GdkEvent* ev);
|
||||
void move_event(double dx, double dy);
|
||||
};
|
||||
|
||||
} // namespace Gnome
|
||||
|
@ -73,17 +73,6 @@ CanvasNoteEvent::validate ()
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
void
|
||||
CanvasNoteEvent::move_event(double dx, double dy)
|
||||
{
|
||||
_item->move(dx, dy);
|
||||
if (_text) {
|
||||
_text->hide();
|
||||
_text->move(dx, dy);
|
||||
_text->show();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CanvasNoteEvent::show_velocity()
|
||||
{
|
||||
|
@ -73,7 +73,7 @@ public:
|
||||
bool selected() const { return _selected; }
|
||||
void selected(bool yn);
|
||||
|
||||
void move_event(double dx, double dy);
|
||||
virtual void move_event(double dx, double dy) = 0;
|
||||
|
||||
uint32_t base_color();
|
||||
|
||||
|
@ -18,5 +18,22 @@ CanvasNote::on_event(GdkEvent* ev)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CanvasNote::move_event(double dx, double dy)
|
||||
{
|
||||
property_x1() = property_x1() + dx;
|
||||
property_y1() = property_y1() + dy;
|
||||
property_x2() = property_x2() + dx;
|
||||
property_y2() = property_y2() + dy;
|
||||
|
||||
if (_text) {
|
||||
_text->hide();
|
||||
_text->property_x() = _text->property_x() + dx;
|
||||
_text->property_y() = _text->property_y() + dy;
|
||||
_text->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace Gnome
|
||||
} // namespace Canvas
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
void hide() { SimpleRect::hide(); }
|
||||
|
||||
bool on_event(GdkEvent* ev);
|
||||
void move_event(double dx, double dy);
|
||||
|
||||
CanvasNote (MidiRegionView& region,
|
||||
Group& group,
|
||||
|
@ -25,17 +25,35 @@ using namespace Gnome::Art;
|
||||
Diamond::Diamond(Group& group, double height)
|
||||
: Polygon(group)
|
||||
{
|
||||
set_height(height);
|
||||
points = gnome_canvas_points_new (4);
|
||||
g_object_set (gobj(), "points", points, NULL);
|
||||
set_height (height);
|
||||
}
|
||||
|
||||
Diamond::~Diamond ()
|
||||
{
|
||||
gnome_canvas_points_free (points);
|
||||
}
|
||||
|
||||
void
|
||||
Diamond::set_height(double height)
|
||||
{
|
||||
Points points;
|
||||
points.push_back(Art::Point(0, height*2.0));
|
||||
points.push_back(Art::Point(height, height));
|
||||
points.push_back(Art::Point(0, 0));
|
||||
points.push_back(Art::Point(-height, height));
|
||||
property_points() = points;
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
get_bounds (x1, y1, x2, y2);
|
||||
|
||||
points->coords[0] = x1;
|
||||
points->coords[1] = y1 + height*2.0;
|
||||
|
||||
points->coords[2] = x2 + height;
|
||||
points->coords[3] = y1 + height;
|
||||
|
||||
points->coords[4] = x1;
|
||||
points->coords[5] = y2;
|
||||
|
||||
points->coords[6] = x2 -height;
|
||||
points->coords[7] = y2 + height;
|
||||
|
||||
g_object_set (gobj(), "points", points, NULL);
|
||||
}
|
||||
|
||||
|
@ -28,11 +28,16 @@ namespace Gnome {
|
||||
namespace Canvas {
|
||||
|
||||
|
||||
class Diamond : public Polygon {
|
||||
public:
|
||||
class Diamond : public Polygon
|
||||
{
|
||||
public:
|
||||
Diamond(Group& group, double height);
|
||||
|
||||
~Diamond ();
|
||||
|
||||
void set_height(double height);
|
||||
|
||||
protected:
|
||||
GnomeCanvasPoints* points;
|
||||
};
|
||||
|
||||
|
||||
|
@ -195,9 +195,9 @@ class Editor : public PublicEditor
|
||||
void add_imageframe_marker_time_axis(const std::string & track_name, TimeAxisView* marked_track, void*) ;
|
||||
void connect_to_image_compositor() ;
|
||||
void scroll_timeaxis_to_imageframe_item(const TimeAxisViewItem* item) ;
|
||||
#endif
|
||||
|
||||
TimeAxisView* get_named_time_axis(const std::string & name) ;
|
||||
#endif /* WITH_CMT */
|
||||
|
||||
void foreach_time_axis_view (sigc::slot<void,TimeAxisView&>);
|
||||
void add_to_idle_resize (TimeAxisView*, int32_t);
|
||||
|
||||
|
@ -45,6 +45,7 @@ using namespace PBD;
|
||||
using namespace sigc;
|
||||
using namespace Gtk;
|
||||
using namespace Editing;
|
||||
using namespace ArdourCanvas;
|
||||
|
||||
double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
|
||||
|
||||
@ -3366,7 +3367,7 @@ MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
|
||||
: Drag (e, i)
|
||||
{
|
||||
ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
|
||||
CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
|
||||
region = &cnote->region_view();
|
||||
}
|
||||
|
||||
@ -3389,7 +3390,7 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
|
||||
last_x = region->snap_to_pixel(event_x);
|
||||
last_y = event_y;
|
||||
|
||||
ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
|
||||
CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
|
||||
|
||||
if (!(was_selected = cnote->selected())) {
|
||||
|
||||
@ -3447,8 +3448,16 @@ NoteDrag::motion (GdkEvent*, bool)
|
||||
dy = streamview->note_height() * this_delta_note;
|
||||
last_y = last_y + dy;
|
||||
}
|
||||
|
||||
region->move_selection (dx, dy);
|
||||
|
||||
if (dx || dy) {
|
||||
region->move_selection (dx, dy);
|
||||
|
||||
CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
|
||||
char buf[4];
|
||||
snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
|
||||
//editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
|
||||
_editor->show_verbose_canvas_cursor_with (buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -63,7 +63,6 @@ Editor::get_named_time_axis(const string & name)
|
||||
}
|
||||
|
||||
/* <CMT Additions file="editor.cc"> */
|
||||
#ifdef HAVE_CMT
|
||||
|
||||
void
|
||||
Editor::add_imageframe_time_axis(const string & track_name, void* src)
|
||||
@ -1115,4 +1114,3 @@ Editor::handle_new_imageframe_marker_time_axis_view(const string & track_name, T
|
||||
|
||||
|
||||
/* </CMT Additions file="editor_route_list.cc"> */
|
||||
#endif /* HAVE_CMT */
|
||||
|
@ -1191,12 +1191,10 @@ MidiRegionView::update_note (CanvasNote* ev)
|
||||
const nframes64_t note_end_frames = beats_to_frames(note->end_time());
|
||||
|
||||
const double x = trackview.editor().frame_to_pixel(note_start_frames - _region->start());
|
||||
|
||||
|
||||
const double y1 = midi_stream_view()->note_to_y(note->note());
|
||||
const double note_endpixel =
|
||||
trackview.editor().frame_to_pixel(note_end_frames - _region->start());
|
||||
|
||||
|
||||
ev->property_x1() = x;
|
||||
ev->property_y1() = y1;
|
||||
if (note->length() > 0) {
|
||||
@ -1237,7 +1235,7 @@ MidiRegionView::update_hit (CanvasHit* ev)
|
||||
const double diamond_size = midi_stream_view()->note_height() / 2.0;
|
||||
const double y = midi_stream_view()->note_to_y(note->note()) + ((diamond_size-2) / 4.0);
|
||||
|
||||
ev->move(x, y);
|
||||
ev->move_event (x, y);
|
||||
}
|
||||
|
||||
/** Add a MIDI note to the view (with length).
|
||||
@ -1680,24 +1678,22 @@ MidiRegionView::move_selection(double dx, double dy)
|
||||
}
|
||||
|
||||
void
|
||||
MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
|
||||
MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, int8_t dnote)
|
||||
{
|
||||
// TODO: This would be faster/nicer with a MoveCommand that doesn't need to copy...
|
||||
if (_selection.find(ev) == _selection.end()) {
|
||||
return;
|
||||
}
|
||||
assert (!_selection.empty());
|
||||
|
||||
uint8_t lowest_note_in_selection = midi_stream_view()->lowest_note();
|
||||
uint8_t highest_note_in_selection = midi_stream_view()->highest_note();
|
||||
uint8_t lowest_note_in_selection = 127;
|
||||
uint8_t highest_note_in_selection = 0;
|
||||
uint8_t highest_note_difference = 0;
|
||||
|
||||
// find highest and lowest notes first
|
||||
|
||||
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
|
||||
uint8_t pitch = (*i)->note()->note();
|
||||
lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
|
||||
highest_note_in_selection = std::max(highest_note_in_selection, pitch);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cerr << "dnote: " << (int) dnote << endl;
|
||||
cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
|
||||
@ -1707,7 +1703,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
|
||||
cerr << "selection size: " << _selection.size() << endl;
|
||||
cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
|
||||
*/
|
||||
|
||||
|
||||
// Make sure the note pitch does not exceed the MIDI standard range
|
||||
if (dnote <= 127 && (highest_note_in_selection + dnote > 127)) {
|
||||
highest_note_difference = highest_note_in_selection - 127;
|
||||
@ -1735,7 +1731,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
|
||||
|
||||
uint8_t original_pitch = (*i)->note()->note();
|
||||
uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
|
||||
|
||||
|
||||
// keep notes in standard midi range
|
||||
clamp_to_0_127(new_pitch);
|
||||
|
||||
@ -1755,7 +1751,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
|
||||
|
||||
// care about notes being moved beyond the upper/lower bounds on the canvas
|
||||
if (lowest_note_in_selection < midi_stream_view()->lowest_note() ||
|
||||
highest_note_in_selection > midi_stream_view()->highest_note()) {
|
||||
highest_note_in_selection > midi_stream_view()->highest_note()) {
|
||||
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
|
||||
}
|
||||
}
|
||||
@ -1918,6 +1914,14 @@ MidiRegionView::commit_resizing (bool at_front, double delta_x, bool relative)
|
||||
|
||||
if (at_front && current_x < canvas_note->note()->end_time()) {
|
||||
diff_add_change (canvas_note, MidiModel::DiffCommand::StartTime, current_x);
|
||||
|
||||
double len = canvas_note->note()->time() - current_x;
|
||||
len += canvas_note->note()->length();
|
||||
|
||||
if (len > 0) {
|
||||
/* XXX convert to beats */
|
||||
diff_add_change (canvas_note, MidiModel::DiffCommand::Length, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (!at_front) {
|
||||
@ -2263,7 +2267,10 @@ MidiRegionView::note_entered(ArdourCanvas::CanvasNoteEvent* ev)
|
||||
}
|
||||
|
||||
PublicEditor& editor (trackview.editor());
|
||||
editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
|
||||
char buf[4];
|
||||
snprintf (buf, sizeof (buf), "%d", (int) ev->note()->note());
|
||||
//editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
|
||||
editor.show_verbose_canvas_cursor_with (buf);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -192,7 +192,7 @@ class MidiRegionView : public RegionView
|
||||
size_t selection_size() { return _selection.size(); }
|
||||
|
||||
void move_selection(double dx, double dy);
|
||||
void note_dropped(ArdourCanvas::CanvasNoteEvent* ev, double d_pixels, uint8_t d_note);
|
||||
void note_dropped(ArdourCanvas::CanvasNoteEvent* ev, double d_pixels, int8_t d_note);
|
||||
|
||||
/** Return true iff the note is within the extent of the region.
|
||||
* @param visible will be set to true if the note is within the visible note range, false otherwise.
|
||||
|
@ -269,9 +269,9 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
|
||||
virtual void add_imageframe_time_axis(const std::string & track_name, void*) = 0;
|
||||
virtual void add_imageframe_marker_time_axis(const std::string & track_name, TimeAxisView* marked_track, void*) = 0;
|
||||
virtual void scroll_timeaxis_to_imageframe_item(const TimeAxisViewItem* item) = 0;
|
||||
virtual TimeAxisView* get_named_time_axis(const std::string & name) = 0;
|
||||
#endif
|
||||
|
||||
virtual TimeAxisView* get_named_time_axis(const std::string & name) = 0;
|
||||
virtual RouteTimeAxisView* get_route_view_by_id (PBD::ID& id) = 0;
|
||||
|
||||
virtual void get_equivalent_regions (RegionView* rv, std::vector<RegionView*>&, ARDOUR::RouteGroup::Property) const = 0;
|
||||
|
@ -359,6 +359,8 @@ ArdourStartup::setup_initial_choice_page ()
|
||||
|
||||
centering_vbox->pack_start (ic_new_session_button, false, true);
|
||||
centering_vbox->pack_start (ic_existing_session_button, false, true);
|
||||
ic_new_session_button.signal_button_press_event().connect(mem_fun(*this, &ArdourStartup::initial_choice_activated), false);
|
||||
ic_existing_session_button.signal_button_press_event().connect(mem_fun(*this, &ArdourStartup::initial_choice_activated), false);
|
||||
|
||||
centering_hbox->pack_start (*centering_vbox, true, true);
|
||||
|
||||
@ -377,6 +379,18 @@ ArdourStartup::setup_initial_choice_page ()
|
||||
set_page_complete (ic_vbox, true);
|
||||
}
|
||||
|
||||
bool
|
||||
ArdourStartup::initial_choice_activated(GdkEventButton *event)
|
||||
{
|
||||
if (event && event->type == GDK_2BUTTON_PRESS && session_page_index != -1)
|
||||
{
|
||||
set_current_page(session_page_index);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ArdourStartup::setup_session_page ()
|
||||
{
|
||||
|
@ -89,6 +89,7 @@ class ArdourStartup : public Gtk::Assistant {
|
||||
Gtk::VBox ic_vbox;
|
||||
Gtk::RadioButton ic_new_session_button;
|
||||
Gtk::RadioButton ic_existing_session_button;
|
||||
bool initial_choice_activated(GdkEventButton *);
|
||||
|
||||
/* monitoring choices */
|
||||
|
||||
|
@ -52,6 +52,7 @@ gtk2_ardour_sources = [
|
||||
'bundle_manager.cc',
|
||||
'cairo_widget.cc',
|
||||
'canvas-flag.cc',
|
||||
'canvas-hit.cc',
|
||||
'canvas-note-event.cc',
|
||||
'canvas-note.cc',
|
||||
'canvas-program-change.cc',
|
||||
@ -79,7 +80,6 @@ gtk2_ardour_sources = [
|
||||
'editor_export_audio.cc',
|
||||
'editor_group_tabs.cc',
|
||||
'editor_hscroller.cc',
|
||||
'editor_imageframe.cc',
|
||||
'editor_keyboard.cc',
|
||||
'editor_keys.cc',
|
||||
'editor_markers.cc',
|
||||
@ -342,7 +342,6 @@ def build(bld):
|
||||
else:
|
||||
key = "_".join (['FONT',sizename])
|
||||
fontstyle = " ".join ([basefont,points])
|
||||
print key
|
||||
font_subst_dict[key] = fontstyle
|
||||
|
||||
# RC files
|
||||
|
@ -26,7 +26,7 @@
|
||||
// Use this define when initializing arrarys for use in sndfile_*_format()
|
||||
#define SNDFILE_STR_LENGTH 32
|
||||
|
||||
#define SNDFILE_HEADER_FORMATS 5
|
||||
#define SNDFILE_HEADER_FORMATS 7
|
||||
extern const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1];
|
||||
extern const char * const sndfile_file_endings_strings[SNDFILE_HEADER_FORMATS+1];
|
||||
|
||||
|
@ -349,13 +349,8 @@ AudioFileSource::safe_audio_file_extension(const ustring& file)
|
||||
".vwe", ".VWE",
|
||||
".paf", ".PAF",
|
||||
".voc", ".VOC",
|
||||
#ifdef HAVE_OGG
|
||||
".ogg", ".OGG",
|
||||
#endif /* HAVE_OGG */
|
||||
#ifdef HAVE_FLAC
|
||||
".flac", ".FLAC",
|
||||
#else
|
||||
#endif // HAVE_FLAC
|
||||
#ifdef HAVE_COREAUDIO
|
||||
".mp3", ".MP3",
|
||||
".aac", ".AAC",
|
||||
|
@ -35,6 +35,8 @@ const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1] = {
|
||||
N_("AIFF"),
|
||||
N_("CAF"),
|
||||
N_("W64 (64 bit WAV)"),
|
||||
N_("FLAC"),
|
||||
N_("Ogg/Vorbis"),
|
||||
N_("raw (no header)"),
|
||||
0
|
||||
};
|
||||
@ -44,6 +46,8 @@ const char* const sndfile_file_endings_strings[SNDFILE_HEADER_FORMATS+1] = {
|
||||
N_(".aiff"),
|
||||
N_(".caf"),
|
||||
N_(".w64"),
|
||||
N_(".flac"),
|
||||
N_(".ogg"),
|
||||
N_(".raw"),
|
||||
0
|
||||
};
|
||||
@ -53,6 +57,8 @@ int sndfile_header_formats[SNDFILE_HEADER_FORMATS] = {
|
||||
SF_FORMAT_AIFF,
|
||||
SF_FORMAT_CAF,
|
||||
SF_FORMAT_W64,
|
||||
SF_FORMAT_FLAC,
|
||||
SF_FORMAT_OGG,
|
||||
SF_FORMAT_RAW
|
||||
};
|
||||
|
||||
|
@ -517,16 +517,7 @@ string_is_affirmative (const std::string& str)
|
||||
{
|
||||
/* to be used only with XML data - not intended to handle user input */
|
||||
|
||||
if (str == "1" || str == "y" || str == "Y") {
|
||||
return true;
|
||||
} else {
|
||||
std::string str_uc;
|
||||
std::transform(str.begin(), str.end(), str_uc.begin(), ::toupper);
|
||||
if (str_uc == "YES") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return str == "1" || str == "y" || str == "Y" || (!g_strncasecmp(str.c_str(), "yes", str.length()));
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
@ -3,6 +3,8 @@ import autowaf
|
||||
import os
|
||||
import glob
|
||||
import Options
|
||||
import re
|
||||
import subprocess
|
||||
from w18n import build_i18n
|
||||
|
||||
# Version of this package (even if built as a child)
|
||||
@ -119,6 +121,7 @@ libardour_sources = [
|
||||
'midi_track.cc',
|
||||
'mix.cc',
|
||||
'mtc_slave.cc',
|
||||
'mtdm.cc',
|
||||
'mute_master.cc',
|
||||
'named_selection.cc',
|
||||
'onset_detector.cc',
|
||||
@ -181,6 +184,20 @@ libardour_sources = [
|
||||
'version.cc'
|
||||
]
|
||||
|
||||
def flac_supported():
|
||||
cmd = subprocess.Popen ("sndfile-info testfile.flac",
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.STDOUT, shell = True)
|
||||
out = cmd.communicate()[0];
|
||||
return re.search ('unknown format', out) == None
|
||||
|
||||
def ogg_supported():
|
||||
cmd = subprocess.Popen ("sndfile-info testfile.ogg",
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.STDOUT, shell = True)
|
||||
out = cmd.communicate()[0];
|
||||
return re.search ('unknown format', out) == None
|
||||
|
||||
def set_options(opt):
|
||||
autowaf.set_options(opt)
|
||||
|
||||
@ -210,12 +227,24 @@ def configure(conf):
|
||||
conf.check(header_name='sys/vfs.h', define_name='HAVE_SYS_VFS_H')
|
||||
conf.check(header_name='wordexp.h', define_name='HAVE_WORDEXP')
|
||||
|
||||
if flac_supported():
|
||||
conf.define ('HAVE_FLAC', 1)
|
||||
autowaf.display_msg(conf, 'Checking for FLAC support', True)
|
||||
else:
|
||||
autowaf.display_msg(conf, 'Checking for FLAC support', False)
|
||||
if ogg_supported():
|
||||
conf.define ('HAVE_OGG', 1)
|
||||
autowaf.display_msg(conf, 'Checking for Ogg/Vorbis support', True)
|
||||
else:
|
||||
autowaf.display_msg(conf, 'Checking for Ogg/Vorbis Support', False)
|
||||
|
||||
conf.write_config_header('libardour-config.h')
|
||||
|
||||
# Boost headers
|
||||
autowaf.check_header(conf, 'boost/shared_ptr.hpp')
|
||||
autowaf.check_header(conf, 'boost/weak_ptr.hpp')
|
||||
|
||||
|
||||
def build(bld):
|
||||
# Library
|
||||
obj = bld.new_task_gen('cxx', 'shlib')
|
||||
|
BIN
testfile.flac
Normal file
BIN
testfile.flac
Normal file
Binary file not shown.
BIN
testfile.ogg
Normal file
BIN
testfile.ogg
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user