plugins/score-plugin-avnd/Crousti/File.hpp
1 #pragma once
2 #include <Media/AudioDecoder.hpp>
3 
4 #include <score/document/DocumentContext.hpp>
5 #include <score/tools/File.hpp>
6 
7 #include <ossia/dataflow/exec_state_facade.hpp>
8 #include <ossia/dataflow/nodes/media.hpp>
9 #include <ossia/network/value/value.hpp>
10 
11 #include <QByteArray>
12 #include <QFile>
13 
14 #include <avnd/binding/ossia/soundfiles.hpp>
15 #include <libremidi/reader.hpp>
16 
17 namespace oscr
18 {
19 
20 namespace
21 {
22 [[nodiscard]] static QString
23 filenameFromPort(const ossia::value& value, const score::DocumentContext& ctx)
24 {
25  if(auto str = value.target<std::string>())
26  return score::locateFilePath(QString::fromStdString(*str).trimmed(), ctx);
27  return {};
28 }
29 
30 // TODO refactor this into a generic explicit soundfile loaded mechanism
31 [[nodiscard]] static auto
32 loadSoundfile(const ossia::value& value, const score::DocumentContext& ctx, double rate)
33 {
34  // Initialize the control with the current soundfile
35  if(auto str = filenameFromPort(value, ctx); !str.isEmpty())
36  {
37  auto dec = Media::AudioDecoder::decode_synchronous(str, rate);
38 
39  if(dec.has_value())
40  {
41  auto hdl = std::make_shared<ossia::audio_data>();
42  hdl->data = std::move(dec->second);
43  hdl->path = str.toStdString();
44  hdl->rate = rate;
45  return hdl;
46  }
47  }
48  return ossia::audio_handle{};
49 }
50 
51 using midifile_handle = std::shared_ptr<oscr::midifile_data>;
52 [[nodiscard]] inline midifile_handle
53 loadMidifile(const ossia::value& value, const score::DocumentContext& ctx)
54 {
55  // Initialize the control with the current soundfile
56  if(auto str = filenameFromPort(value, ctx); !str.isEmpty())
57  {
58  QFile f(str);
59  if(!f.open(QIODevice::ReadOnly))
60  return {};
61  auto ptr = f.map(0, f.size());
62 
63  auto hdl = std::make_shared<oscr::midifile_data>();
64  if(auto ret = hdl->reader.parse((uint8_t*)ptr, f.size());
65  ret == libremidi::reader::invalid)
66  return {};
67 
68  hdl->filename = str.toStdString();
69  return hdl;
70  }
71  return {};
72 }
73 
74 using raw_file_handle = std::shared_ptr<raw_file_data>;
75 [[nodiscard]] inline raw_file_handle loadRawfile(
76  const ossia::value& value, const score::DocumentContext& ctx, bool text, bool mmap)
77 {
78  // Initialize the control with the current soundfile
79  if(auto filename = filenameFromPort(value, ctx); !filename.isEmpty())
80  {
81  if(!QFile::exists(filename))
82  return {};
83 
84  auto hdl = std::make_shared<oscr::raw_file_data>();
85  hdl->file.setFileName(filename);
86  if(!hdl->file.open(QIODevice::ReadOnly))
87  return {};
88 
89  if(mmap)
90  {
91  auto map = (char*)hdl->file.map(0, hdl->file.size());
92  hdl->data = QByteArray::fromRawData(map, hdl->file.size());
93  }
94  else
95  {
96  if(text)
97  hdl->file.setTextModeEnabled(true);
98 
99  hdl->data = hdl->file.readAll();
100  }
101  hdl->filename = filename.toStdString();
102  return hdl;
103  }
104  return {};
105 }
106 
107 [[nodiscard]] inline auto loadSoundfile(
108  const ossia::value& value, const score::DocumentContext& ctx,
109  const std::shared_ptr<ossia::execution_state>& st)
110 {
111  const double rate = ossia::exec_state_facade{st.get()}.sampleRate();
112  return loadSoundfile(value, ctx, rate);
113 }
114 
115 template <typename Field>
116 static auto executePortPreprocess(auto& file)
117 {
118  using field_file_type = decltype(Field::file);
119  field_file_type ffile;
120  ffile.bytes = decltype(ffile.bytes)(file.data.constData(), file.file.size());
121  ffile.filename = file.filename;
122  return Field::process(ffile);
123 }
124 
125 }
126 
127 }
Definition: Factories.hpp:19
QString locateFilePath(const QString &filename, const score::DocumentContext &ctx) noexcept
Definition: File.cpp:57
Definition: DocumentContext.hpp:18