Loading...
Searching...
No Matches
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
17namespace oscr
18{
19
20namespace
21{
22[[nodiscard]] static QString
23filenameFromPort(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// Resolve <PROJECT>: / <LIBRARY>: / document-relative paths for a path-valued
31// string control (e.g. a folder_port) exactly like the file ports above do, so
32// the object sees an absolute path instead of the raw library-relative string.
33// A non-string or empty value is returned unchanged (an unset control stays
34// empty rather than resolving to the document folder).
35[[nodiscard]] static ossia::value
36resolvePathValue(const ossia::value& value, const score::DocumentContext& ctx)
37{
38 if(auto str = value.target<std::string>(); str && !str->empty())
39 {
40 const QString resolved
41 = score::locateFilePath(QString::fromStdString(*str).trimmed(), ctx);
42 if(!resolved.isEmpty())
43 return ossia::value{resolved.toStdString()};
44 }
45 return value;
46}
47
48// TODO refactor this into a generic explicit soundfile loaded mechanism
49[[nodiscard]] static auto
50loadSoundfile(const ossia::value& value, const score::DocumentContext& ctx, double rate)
51{
52 // Initialize the control with the current soundfile
53 if(auto str = filenameFromPort(value, ctx); !str.isEmpty())
54 {
55 auto dec = Media::AudioDecoder::decode_synchronous(str, rate);
56
57 if(dec.has_value())
58 {
59 auto hdl = std::make_shared<ossia::audio_data>();
60 hdl->data = std::move(dec->second);
61 hdl->path = str.toStdString();
62 hdl->rate = rate;
63 return hdl;
64 }
65 }
66 return ossia::audio_handle{};
67}
68
69using midifile_handle = std::shared_ptr<oscr::midifile_data>;
70[[nodiscard]] inline midifile_handle
71loadMidifile(const ossia::value& value, const score::DocumentContext& ctx)
72{
73 // Initialize the control with the current soundfile
74 if(auto str = filenameFromPort(value, ctx); !str.isEmpty())
75 {
76 QFile f(str);
77 if(!f.open(QIODevice::ReadOnly))
78 return {};
79 auto ptr = f.map(0, f.size());
80
81 auto hdl = std::make_shared<oscr::midifile_data>();
82 if(auto ret = hdl->reader.parse((uint8_t*)ptr, f.size());
83 ret == libremidi::reader::invalid)
84 return {};
85
86 hdl->filename = str.toStdString();
87 return hdl;
88 }
89 return {};
90}
91
92using raw_file_handle = std::shared_ptr<raw_file_data>;
93[[nodiscard]] inline raw_file_handle loadRawfile(
94 const ossia::value& value, const score::DocumentContext& ctx, bool text, bool mmap)
95{
96 // Initialize the control with the current soundfile
97 if(auto filename = filenameFromPort(value, ctx); !filename.isEmpty())
98 {
99 if(!QFile::exists(filename))
100 return {};
101
102 auto hdl = std::make_shared<oscr::raw_file_data>();
103 hdl->file.setFileName(filename);
104 if(!hdl->file.open(QIODevice::ReadOnly))
105 return {};
106
107 if(mmap)
108 {
109 auto map = (char*)hdl->file.map(0, hdl->file.size());
110 hdl->data = QByteArray::fromRawData(map, hdl->file.size());
111 }
112 else
113 {
114 if(text)
115 hdl->file.setTextModeEnabled(true);
116
117 hdl->data = hdl->file.readAll();
118 }
119 hdl->filename = filename.toStdString();
120 return hdl;
121 }
122 return {};
123}
124
125[[nodiscard]] inline auto loadSoundfile(
126 const ossia::value& value, const score::DocumentContext& ctx,
127 const std::shared_ptr<ossia::execution_state>& st)
128{
129 const double rate = ossia::exec_state_facade{st.get()}.sampleRate();
130 return loadSoundfile(value, ctx, rate);
131}
132
133template <typename Field>
134static auto executePortPreprocess(auto& file)
135{
136 using field_file_type = decltype(Field::file);
137 field_file_type ffile;
138 ffile.bytes = decltype(ffile.bytes)(file.data.constData(), file.file.size());
139 ffile.filename = file.filename;
140 return Field::process(ffile);
141}
142
143}
144
145}
Definition Factories.hpp:19
QString locateFilePath(const QString &filename, const score::DocumentContext &ctx) noexcept
Definition File.cpp:83
Definition DocumentContext.hpp:18