Codebase list elektroid / 4371abc
Update upstream source from tag 'upstream/2.3' Update to upstream version '2.3' with Debian dir e47f8d46ecafd1e059d1eab2702c5d1712cfa847 Dennis Braun 1 year, 4 months ago
75 changed file(s) with 15653 addition(s) and 9632 deletion(s). Raw diff Collapse all Expand all
3131 *.lo
3232 *.gcno
3333 *.gcda
34 .dirstamp
3435 src/elektroid
3536 src/elektroid-cli
3637 src/*~
00 # Elektroid
11
2 Elektroid is a GNU/Linux transfer application for Elektron devices. It includes the `elektroid` GUI application and the `elektroid-cli` CLI application.
3 Elektroid has been reported to work with Model:Samples, Model:Cycles, Digitakt, Digitone, Syntakt, and Analog Rytm MKI and MKII.
4
5 To use Elektroid, USB configuration must be set to `USB MIDI` or `USB AUDIO/MIDI` as it won't work in Overbridge mode.
2 Elektroid is a GNU/Linux management application for MIDI devices. It includes the `elektroid` GUI application and the `elektroid-cli` CLI application.
3
4 Supported devices:
5
6 * Elektron Model:Samples
7 * Elektron Model:Cycles
8 * Elektron Digitakt
9 * Elektron Digitone and Digitone Keys
10 * Elektron Syntakt
11 * Elektron Analog Rytm MKI and MKII
12 * Elektron Analog Four MKI, MKII and Keys
13 * All samplers implementing MIDI SDS
14 * Casio CZ-101 presets
15 * Arturia MicroBrute sequences
16 * Eventide ModFactor, PitchFactor, TimeFactor, Space and H9 presets
17
18 To use with Elektron devices, USB configuration must be set to `USB MIDI` or `USB AUDIO/MIDI` as it won't work in Overbridge mode.
619
720 ## Installation
821
6073
6174 `elektroid-cli` brings the same functionality as `elektroid` to the command line.
6275
63 There are device commands and filesystem commands. The latter have the form `a-b` where `a` is a command and `b` is a filesystem, (e.g., `ls-project`, `download-sound`, `mkdir-sample`). Notice that the filesystem is always in the singular form and some older commands are deprecated but kept for compatibility reasons although there are not documented here.
64
65 These are the available filesystems:
76 There are device commands and filesystem commands. The latter have the form `a-b-c` where `a` is a connector, `b` is a filesystem and `c` is the command, (e.g., `elektron-project-ls`, `cz-program-upload`, `sds-sample-download`). Notice that the filesystem is always in the singular form. As of version 2.2, **older command forms have been removed**.
77
78 These are the available commands:
79
80 * `ls` or `list`
81 * `mkdir` (behave as `mkdir -p`)
82 * `rmdir` or `rm` (both behave as `rm -rf`)
83 * `mv` (in slot mode, the second path is just the name of the file)
84 * `cp`
85 * `cl`, clear item
86 * `sw`, swap items
87 * `ul` or `upload`
88 * `dl` or `download`
89
90 Keep in mind that not every filesystem implements all the commands. For instance, Elektron samples can not be swapped.
91
92 Provided paths must always be prepended with the device id and a colon (e.g., `0:/incoming`). In slot mode filesystems, (these are the most typically used), items are addressed by number and destination paths take the form `path:name` (e.g., `0:/0:bass`) when uploading.
93
94 ### Device commands
95
96 * `ld` or `ls-devices`, list all MIDI devices with input and output
97
98 ```
99 $ elektroid-cli ld
100 0: hw:2,0,0 Elektron Digitakt MIDI 1
101 1: hw:4,0,0 padKONTROL MIDI 1
102 2: hw:4,0,1 padKONTROL MIDI 2
103 ```
104
105 * `info` or `info-device`, show device info including device filesystems
106
107 ```
108 $ elektroid-cli info 0
109 Digitakt 1.30 (Digitakt) filesystems=sample,data,project,sound
110 ```
111
112 * `df` or `info-storage`, show size and use of +Drive and RAM
113
114 ```
115 $ elektroid-cli df 0
116 Storage Size Used Available Use%
117 +Drive 959.50MiB 198.20MiB 761.30MiB 20.66%
118 RAM 64.00MiB 13.43MiB 50.57MiB 20.98%
119 ```
120
121 * `send` and `receive` work with a batch of SysEx messages. These are useful when working with generic devices, which have no filesystems implemented buf offer options to receive or send data.
122
123 ```
124 $ elektroid-cli send file.syx 0:/
125 $ elektroid-cli receive 0:/
126 ```
127
128 * `upgrade`, upgrade firmware
129
130 ```
131 $ elektroid-cli upgrade Digitakt_OS1.30.syx 0
132 ```
133
134 ### Elektron conector
135
136 These are the available filesystems for the elektron connector:
66137
67138 * `sample`
68139 * `raw`
73144
74145 Raw and data are intended to interface directly with the filesystems provided by the devices so the downloaded or uploaded files are **not** compatible with Elektron Transfer formats. Preset is a particular instance of raw and so are project and sound but regarding data. Thus, raw and data filesystems should be used only for testing and are **not** available in the GUI.
75146
76 These are the available commands:
77
78 * `ls` or `list`
79 * `mkdir`
80 * `rmdir` or `rm` (both behave as `rm -rf`)
81 * `mv`
82 * `cp`
83 * `cl`, clear item
84 * `sw`, swap items
85 * `ul` or `upload`
86 * `dl` or `download`
87
88 Keep in mind that not every filesystem implements all the commands. For instance, samples can not be swapped.
89
90 Provided paths must always be prepended with the device id and a colon (':') e.g., `0:/incoming`.
91
92 ### Device commands
93
94 * `ld` or `ls-devices`, list compatible devices
95
96 ```
97 $ elektroid-cli ld
98 0 Elektron Digitakt MIDI 1
99 ```
100
101 * `info` or `info-device`, show device info including device filesystems
102
103 ```
104 $ elektroid-cli info 0
105 Digitakt 1.30 (Digitakt) filesystems=sample,data,project,sound
106 ```
107
108 * `df` or `info-storage`, show size and use of +Drive and RAM
109
110 ```
111 $ elektroid-cli df 0
112 Storage Size Used Available Use%
113 +Drive 959.50MiB 198.20MiB 761.30MiB 20.66%
114 RAM 64.00MiB 13.43MiB 50.57MiB 20.98%
115 ```
116
117 * `upgrade`, upgrade firmware
118
119 ```
120 $ elektroid-cli upgrade Digitakt_OS1.30.syx 0
121 ```
122
123 ### Sample, raw and preset commands
124
125 * `ls-sample`
147 #### Sample, raw and preset commands
148
149 * `elektron-sample-ls`
126150
127151 It only works for directories. Notice that the first column is the file type, the second is the size, the third is an internal cksum and the last one is the sample name.
128152
129153 ```
130 $ elektroid-cli ls-sample 0:/
154 $ elektroid-cli elektron-sample-ls 0:/
131155 D 0B 00000000 drum machines
132156 F 630.34KiB f8711cd9 saw
133157 F 1.29MiB 0bbc22bd square
134158 ```
135159
136 * `mkdir-sample`
137
138 ```
139 $ elektroid-cli mkdir-sample 0:/samples
140 ```
141
142 * `rmdir-sample`
143
144 ```
145 $ elektroid-cli rmdir-sample 0:/samples
146 ```
147
148 * `ul-sample`
149
150 ```
151 $ elektroid-cli ul-sample square.wav 0:/
152 ```
153
154 * `dl-sample`
155
156 ```
157 $ elektroid-cli dl-sample 0:/square
158 ```
159
160 * `mv-sample`
161
162 ```
163 $ elektroid-cli mv-sample 0:/square 0:/sample
164 ```
165
166 * `rm-sample`
167
168 ```
169 $ elektroid-cli rm-sample 0:/sample
170 ```
171
172 ### Data, sound and project commands
160 * `elektron-sample-mkdir`
161
162 ```
163 $ elektroid-cli elektron-sample-mkdir 0:/samples
164 ```
165
166 * `elektron-sample-rmdir`
167
168 ```
169 $ elektroid-cli elektron-sample-rmdir 0:/samples
170 ```
171
172 * `elektron-sample-ul`
173
174 ```
175 $ elektroid-cli elektron-sample-ul square.wav 0:/
176 ```
177
178 * `elektron-sample-dl`
179
180 ```
181 $ elektroid-cli elektron-sample-dl 0:/square
182 ```
183
184 * `elektron-sample-mv`
185
186 ```
187 $ elektroid-cli elektron-sample-mv 0:/square 0:/sample
188 ```
189
190 * `elektron-sample-rm`
191
192 ```
193 $ elektroid-cli elektron-sample-rm 0:/sample
194 ```
195
196 #### Data, sound and project commands
173197
174198 There are a few things to clarify first.
175199
179203
180204 Here are the commands.
181205
182 * `ls-data`
206 * `elektron-data-ls`
183207
184208 It only works for directories. Notice that the first column is the file type, the second is the index, the third is the permissons in hexadecimal, the fourth indicates if the data in valid, the fifth indicates if it has metadatam, the sixth is the size and the last one is the item name.
185209
186210 Permissions are 16 bits values but only 6 are used from bit 2 to bit 7 both included. From LSB to MSB, this permissions are read, write, clear, copy, swap, and move.
187211
188212 ```
189 $ elektroid-cli ls-data 0:/
213 $ elektroid-cli elektron-data-ls 0:/
190214 D -1 0000 0 0 0B projects
191215 D -1 0000 0 0 0B soundbanks
192216 ```
193217
194218 ```
195 $ elektroid-cli ls-data 0:/soundbanks/D
219 $ elektroid-cli elektron-data-ls 0:/soundbanks/D
196220 F 1 0012 1 1 160B KICK
197221 F 2 0012 1 1 160B SNARE
198222 ```
199223
200 * `cp-data`
201
202 ```
203 $ elektroid-cli cp-data 0:/soundbanks/D/1 0:/soundbanks/D/3
204 $ elektroid-cli ls-data 0:/soundbanks/D
224 * `elektron-data-cp`
225
226 ```
227 $ elektroid-cli elektron-data-cp 0:/soundbanks/D/1 0:/soundbanks/D/3
228 $ elektroid-cli elektron-data-ls 0:/soundbanks/D
205229 F 1 0012 1 1 160B KICK
206230 F 2 0012 1 1 160B SNARE
207231 F 3 0012 1 1 160B KICK
208232 ```
209233
210 * `sw-data`
211
212 ```
213 $ elektroid-cli sw-data 0:/soundbanks/D/2 0:/soundbanks/D/3
214 $ elektroid-cli ls-data 0:/soundbanks/D
234 * `elektron-data-sw`
235
236 ```
237 $ elektroid-cli elektron-data-sw 0:/soundbanks/D/2 0:/soundbanks/D/3
238 $ elektroid-cli elektron-data-ls 0:/soundbanks/D
215239 F 1 0012 1 1 160B KICK
216240 F 2 0012 1 1 160B KICK
217241 F 3 0012 1 1 160B SNARE
218242 ```
219243
220 * `mv-data`
221
222 ```
223 $ elektroid-cli mv-data 0:/soundbanks/D/3 0:/soundbanks/D/1
224 $ elektroid-cli ls-data 0:/soundbanks/D
244 * `elektron-data-mv`
245
246 ```
247 $ elektroid-cli elektron-data-mv 0:/soundbanks/D/3 0:/soundbanks/D/1
248 $ elektroid-cli elektron-data-ls 0:/soundbanks/D
225249 F 1 0012 1 1 160B SNARE
226250 F 2 0012 1 1 160B KICK
227251 ```
228252
229 * `cl-data`
230
231 ```
232 $ elektroid-cli cl-data 0:/soundbanks/D/1
233 $ elektroid-cli ls-data 0:/soundbanks/D
253 * `elektron-data-cl`
254
255 ```
256 $ elektroid-cli elektron-data-cl 0:/soundbanks/D/1
257 $ elektroid-cli elektron-data-ls 0:/soundbanks/D
234258 F 2 0012 1 1 160B KICK
235259 ```
236260
237 * `dl-data`
238
239 ```
240 $ elektroid-cli dl-data 0:/soundbanks/D/1
241 ```
242
243 * `ul-data`
244
245 ```
246 $ elektroid-cli ul-data sound 0:/soundbanks/D
247 ```
248
249 ## Adding and reconfiguring devices
261 * `elektron-data-dl`
262
263 ```
264 $ elektroid-cli elektron-data-dl 0:/soundbanks/D/1
265 ```
266
267 * `elektron-data-ul`
268
269 ```
270 $ elektroid-cli elektron-data-ul sound 0:/soundbanks/D
271 ```
272
273 ## Adding and reconfiguring Elektron devices
250274
251275 Since version 2.1, it is possible to add and reconfigure devices without recompiling as the device definitions are stored in a JSON file. Hopefully, this approach will make it easier for users to modify and add devices and new releases will only be needed if new funcionalities are actually added.
252276
253 This is a device definition from `res/devices.json`.
277 This is a device definition from `res/elektron-devices.json`.
254278
255279 ```
256280 }, {
262286 }, {
263287 ```
264288
265 Properties `filesystems` and `storage` are based on the definitions found in `src/connector.h` and are the bitwise OR result of all the supported filesystems and storage types.
289 Properties `filesystems` and `storage` are based on the definitions found in `src/connectors/elektron.h` and are the bitwise OR result of all the supported filesystems and storage types.
266290
267291 ```
268292 enum connector_fs
284308 };
285309 ```
286310
287 If the file `~/.config/elektroid/devices.json` is found, it will take precedence over the installed one.
311 If the file `~/.config/elektroid/elektron-devices.json` is found, it will take precedence over the installed one.
312
313 ## Running tests
314
315 Elektroid includes automated integration tests for the supported devices and filesystems.
316
317 In order to run a test, proceed as follows. The variable `TEST_DEVICE` must contain the device id and variable `TEST_CONNECTOR_FILESYSTEM` must contain the connector name, an underscore char (`_`) and the filesystem name.
318
319 ```
320 $ TEST_DEVICE=0 TEST_CONNECTOR_FILESYSTEM=efactor_preset make check
321 ```
322
323 Running `make check` without setting any of these variables will succeed and no test will be ran.
11 # Process this file with autoconf to produce a configure script.
22
33 AC_PREREQ([2.69])
4 AC_INIT([elektroid],[2.1],[dagargo@gmail.com])
4 AC_INIT([elektroid],[2.3],[dagargo@gmail.com])
55 AC_CONFIG_SRCDIR([src])
66 AC_CONFIG_HEADERS([config.h])
7 AM_PROG_LIBTOOL
7 LT_INIT
88 AC_SEARCH_LIBS([sqrt], [m])
99 AC_CONFIG_MACRO_DIRS([m4])
10 AM_INIT_AUTOMAKE
10 AM_INIT_AUTOMAKE([subdir-objects])
1111
1212 # Checks for programs.
1313 AC_PROG_CC
00 Name: elektroid
1 Version: 2.0
1 Version: 2.1
22 Release: 1%{?dist}
33 Summary: Transfer application for Elektron devices
44
55 License: GPLv3+
66 URL: https://github.com/dagargo/elektroid
7 Source0: https://github.com/dagargo/elektroid/archive/elektroid-%{version}.tar.gz
7 Source0: https://github.com/dagargo/elektroid/releases/download/%{version}/%{name}-%{version}.tar.gz
88
99 BuildRequires: autoconf
1010 BuildRequires: libtool
3535 Elektroid has been reported to work with Model:Samples, Model:Cycles, Digitakt,
3636 Digitone and Analog Rytm MKI and MKII.
3737
38 %package cli
39 Summary: Transfer application for Elektron devices
40
41 %description cli
42 This is the command-line client for Elektroid.
43
3844
3945 %prep
4046 %autosetup -p1
5359
5460
5561 %files
56 %{_bindir}/elektroid-cli
5762 %{_bindir}/elektroid
5863 %{_datadir}/applications/%{name}.desktop
59 %{_datadir}/%{name}/res/gui.css
60 %{_datadir}/%{name}/res/gui.glade
64 %{_datadir}/%{name}/devices.json
65 %{_datadir}/%{name}/gui.css
66 %{_datadir}/%{name}/gui.glade
6167 %{_datadir}/icons/hicolor/scalable/apps/%{name}.svg
6268 %{_datadir}/icons/hicolor/scalable/apps/%{name}-symbolic.svg
6369 %{_datadir}/icons/hicolor/scalable/apps/%{name}-data-symbolic.svg
6571 %{_datadir}/icons/hicolor/scalable/apps/%{name}-sound-symbolic.svg
6672 %{_datadir}/icons/hicolor/scalable/apps/%{name}-wave-symbolic.svg
6773 %{_datadir}/locale/*/LC_MESSAGES/%{name}.mo
68 %{_mandir}/man1/elektroid-cli.1.gz
6974 %{_mandir}/man1/elektroid.1.gz
7075 %{_metainfodir}/%{name}.appdata.xml
7176 %license COPYING
7277
78 %files cli
79 %{_bindir}/elektroid-cli
80 %{_datadir}/%{name}/devices.json
81 %{_datadir}/locale/*/LC_MESSAGES/%{name}.mo
82 %{_mandir}/man1/elektroid-cli.1.gz
83 %license COPYING
84
7385
7486 %changelog
87 * Wed Jun 08 2022 Jonathan Wakely <jwakely@redhat.com> - 2.1-1
88 - Update to 2.1 release
89
90 * Wed Jun 08 2022 Jonathan Wakely <jwakely@redhat.com> - 2.0-2
91 - Add subpackage for elektroid-cli
92
7593 * Mon Feb 07 2022 Jonathan Wakely <jwakely@fedoraproject.org> - 2.0-1
7694 - RPM package for Fedora
0 src/connector.c
01 src/elektroid.c
2 src/local.c
3 src/connectors/sds.c
14 res/gui.glade
+230
-174
po/ca.po less more
44 #
55 msgid ""
66 msgstr ""
7 "Project-Id-Version: elektroid 1.4\n"
7 "Project-Id-Version: elektroid 2.2\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2022-06-03 08:47+0200\n"
9 "POT-Creation-Date: 2022-10-30 20:46+0100\n"
1010 "PO-Revision-Date: 2020-04-26 13:00+0100\n"
1111 "Last-Translator: David García Goñi <dagargo@gmail.com>\n"
1212 "Language-Team: Catalan\n"
1616 "Content-Transfer-Encoding: 8bit\n"
1717 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1818
19 #: src/elektroid.c:246
20 msgid "Samples"
21 msgstr "Mostres"
22
23 #: src/elektroid.c:248
24 msgid "Presets"
25 msgstr "Programes"
26
27 #: src/elektroid.c:250
28 msgid "Projects"
29 msgstr "Projectes"
30
31 #: src/elektroid.c:252
32 msgid "Sounds"
33 msgstr "Sos"
34
35 #: src/elektroid.c:254 src/elektroid.c:1689 src/elektroid.c:1703
19 #: src/connector.c:41 src/connector.c:47
20 msgid "MIDI device"
21 msgstr "Dispositiu MIDI"
22
23 #: src/elektroid.c:526 src/elektroid.c:3952
24 msgid "Not connected"
25 msgstr "No connectat"
26
27 #: src/elektroid.c:676
28 msgid "Cancelling..."
29 msgstr "Cancel·lant..."
30
31 #: src/elektroid.c:697 src/elektroid.c:2497 src/elektroid.c:2706
32 #: src/elektroid.c:3362
33 msgid "Waiting..."
34 msgstr "Esperant..."
35
36 #: src/elektroid.c:700
37 msgid "Sending..."
38 msgstr "Enviant..."
39
40 #: src/elektroid.c:703
41 msgid "Receiving..."
42 msgstr "Rebent..."
43
44 #: src/elektroid.c:763
45 msgid "Receive SysEx"
46 msgstr "Rep SysEx"
47
48 #: src/elektroid.c:795
49 msgid "Save SysEx"
50 msgstr "Alça SysEx"
51
52 #: src/elektroid.c:798 src/elektroid.c:928 src/elektroid.c:1160
53 #: res/gui.glade:1617 res/gui.glade:1717
54 msgid "_Cancel"
55 msgstr "_Cancel·la"
56
57 #: src/elektroid.c:800 res/gui.glade:1631
58 msgid "_Save"
59 msgstr "_Alça"
60
61 #: src/elektroid.c:804
62 msgid "Received SysEx"
63 msgstr "SysEx rebut"
64
65 #: src/elektroid.c:809 src/elektroid.c:934
66 msgid "SysEx Files"
67 msgstr "Fitxers SysEx"
68
69 #: src/elektroid.c:843
70 #, c-format
71 msgid "Error while saving “%s”: %s."
72 msgstr "Error al guardar «%s»: %s."
73
74 #: src/elektroid.c:864
75 #, c-format
76 msgid "Error while loading “%s”: %s."
77 msgstr "Error al carregar «%s»: %s."
78
79 #: src/elektroid.c:925
80 msgid "Open SysEx"
81 msgstr "Obri SysEx"
82
83 #: src/elektroid.c:930
84 msgid "_Open"
85 msgstr "_Obri"
86
87 #: src/elektroid.c:946
88 msgid "Sending SysEx"
89 msgstr "Enviant SysEx"
90
91 #: src/elektroid.c:1021
92 msgid "minutes"
93 msgstr "minuts"
94
95 #: src/elektroid.c:1159
96 msgid "Are you sure you want to delete the selected items?"
97 msgstr "Està segur de que vol eliminar els elements seleccionats?"
98
99 #: src/elektroid.c:1161
100 msgid "_Delete"
101 msgstr "_Elimina"
102
103 #: src/elektroid.c:1178
104 msgid "Deleting Files"
105 msgstr "Eliminant fitxers"
106
107 #: src/elektroid.c:1179
108 msgid "Deleting..."
109 msgstr "Eliminant..."
110
111 #: src/elektroid.c:1212 res/gui.glade:121 res/gui.glade:210
112 msgid "Rename"
113 msgstr "Canvia el nom"
114
115 #: src/elektroid.c:1228
116 #, c-format
117 msgid "Error while renaming to “%s”: %s."
118 msgstr "Error al canviar el nom a «%s»: %s."
119
120 #: src/elektroid.c:1907 res/gui.glade:572 res/gui.glade:788
121 msgid "Add Directory"
122 msgstr "Afig directori"
123
124 #: src/elektroid.c:1925
125 #, c-format
126 msgid "Error while creating dir “%s”: %s."
127 msgstr "Error al crear el directori «%s»: %s."
128
129 #: src/elektroid.c:1997
130 msgid "Queued"
131 msgstr "A la cua"
132
133 #: src/elektroid.c:1999
134 msgid "Running"
135 msgstr "Executant"
136
137 #: src/elektroid.c:2001
138 msgid "Completed"
139 msgstr "Completada"
140
141 #: src/elektroid.c:2003
142 msgid "Completed with errors"
143 msgstr "Completada amb errors"
144
145 #: src/elektroid.c:2005
146 msgid "Canceled"
147 msgstr "Cancel·lada"
148
149 #: src/elektroid.c:2007 src/elektroid.c:2021
36150 msgid "Undefined"
37151 msgstr "Indefinit"
38152
39 #: src/elektroid.c:434
40 #, c-format
41 msgid "Connected to %s%s"
42 msgstr "Connectat a %s%s"
43
44 #: src/elektroid.c:442 src/elektroid.c:3256
45 msgid "Not connected"
46 msgstr "No connectat"
47
48 #: src/elektroid.c:585
49 msgid "Waiting..."
50 msgstr "Esperant..."
51
52 #: src/elektroid.c:588
53 msgid "Sending..."
54 msgstr "Enviant..."
55
56 #: src/elektroid.c:592
57 msgid "Receiving..."
58 msgstr "Rebent..."
59
60 #: src/elektroid.c:660
61 msgid "Receive SysEx"
62 msgstr "Rep SysEx"
63
64 #: src/elektroid.c:684
65 msgid "Save SysEx"
66 msgstr "Alça SysEx"
67
68 #: src/elektroid.c:687 src/elektroid.c:783 src/elektroid.c:951
69 #: res/gui.glade:1332 res/gui.glade:1432
70 msgid "_Cancel"
71 msgstr "_Cancel·la"
72
73 #: src/elektroid.c:689 res/gui.glade:1346
74 msgid "_Save"
75 msgstr "_Alça"
76
77 #: src/elektroid.c:693
78 msgid "Received SysEx"
79 msgstr "SysEx rebut"
80
81 #: src/elektroid.c:698 src/elektroid.c:789
82 msgid "SysEx Files"
83 msgstr "Fitxers SysEx"
84
85 #: src/elektroid.c:732
86 #, c-format
87 msgid "Error while saving “%s”: %s."
88 msgstr "Error al guardar «%s»: %s."
89
90 #: src/elektroid.c:780
91 msgid "Open SysEx"
92 msgstr "Obri SysEx"
93
94 #: src/elektroid.c:785
95 msgid "_Open"
96 msgstr "_Obri"
97
98 #: src/elektroid.c:806
99 #, c-format
100 msgid "Error while loading “%s”: %s."
101 msgstr "Error al carregar «%s»: %s."
102
103 #: src/elektroid.c:816
104 msgid "Send SysEx"
105 msgstr "Envia SysEx"
106
107 #: src/elektroid.c:918
108 #, c-format
109 msgid "Error while deleting “%s”: %s."
110 msgstr "Error al eliminar «%s»: %s."
111
112 #: src/elektroid.c:950
113 msgid "Are you sure you want to delete the selected items?"
114 msgstr "Està segur de que vol eliminar els elements seleccionats?"
115
116 #: src/elektroid.c:952
117 msgid "_Delete"
118 msgstr "_Elimina"
119
120 #: src/elektroid.c:1005 res/gui.glade:121 res/gui.glade:174
121 msgid "Rename"
122 msgstr "Canvia el nom"
123
124 #: src/elektroid.c:1023
125 #, c-format
126 msgid "Error while renaming to “%s”: %s."
127 msgstr "Error al canviar el nom a «%s»: %s."
128
129 #: src/elektroid.c:1589 res/gui.glade:436 res/gui.glade:606
130 msgid "Add Directory"
131 msgstr "Afig directori"
132
133 #: src/elektroid.c:1607
134 #, c-format
135 msgid "Error while creating dir “%s”: %s."
136 msgstr "Error al crear el directori «%s»: %s."
137
138 #: src/elektroid.c:1679
139 msgid "Queued"
140 msgstr "A la cua"
141
142 #: src/elektroid.c:1681
143 msgid "Running"
144 msgstr "Executant"
145
146 #: src/elektroid.c:1683
147 msgid "Completed"
148 msgstr "Completada"
149
150 #: src/elektroid.c:1685
151 msgid "Completed with errors"
152 msgstr "Completada amb errors"
153
154 #: src/elektroid.c:1687
155 msgid "Canceled"
156 msgstr "Cancel·lada"
157
158 #: src/elektroid.c:1699
153 #: src/elektroid.c:2017
159154 msgid "Upload"
160155 msgstr "Càrrega"
161156
162 #: src/elektroid.c:1701
157 #: src/elektroid.c:2019
163158 msgid "Download"
164159 msgstr "Descàrrega"
165160
166 #: src/elektroid.c:2560 src/elektroid.c:2601
167 #, c-format
168 msgid "Error while moving from “%s” to “%s”: %s."
169 msgstr "Error al moure de «%s» a «%s»: %s."
161 #: src/elektroid.c:2496 src/elektroid.c:2705 src/elektroid.c:3361
162 msgid "Preparing Tasks"
163 msgstr "Preparant tasques..."
164
165 #: src/elektroid.c:3077
166 msgid "Connecting to Device"
167 msgstr "Connectant amb el dispositiu"
168
169 #: src/elektroid.c:3078
170 msgid "Connecting..."
171 msgstr "Conectant..."
172
173 #: src/elektroid.c:3088
174 #, c-format
175 msgid "Device “%s” not recognized: %s"
176 msgstr "Dispositiu «%s» no reconegut: %s"
177
178 #: src/elektroid.c:3355
179 msgid "Moving Files"
180 msgstr "Movent fitxers"
181
182 #: src/elektroid.c:3356
183 msgid "Moving..."
184 msgstr "Movent..."
185
186 #: src/local.c:492
187 msgid "System"
188 msgstr "Sistema"
189
190 #: src/connectors/sds.c:1127 src/connectors/sds.c:1133
191 msgid "SDS sampler"
192 msgstr "Mostrador SDS"
170193
171194 #: res/gui.glade:70
172195 msgid "Upload Selection"
173196 msgstr "Carrega la selecció"
174197
175 #: res/gui.glade:85
198 #: res/gui.glade:85 res/gui.glade:174
176199 msgid "Play"
177200 msgstr "Reproduïx"
178201
179 #: res/gui.glade:99
202 #: res/gui.glade:99 res/gui.glade:188
180203 msgid "Open With External Editor"
181204 msgstr "Obri amb l'editor extern"
182205
183 #: res/gui.glade:107
206 #: res/gui.glade:107 res/gui.glade:196
184207 msgid "Show in File Manager"
185208 msgstr "Mostra al navegador de fitxers"
186209
187 #: res/gui.glade:130 res/gui.glade:183
210 #: res/gui.glade:130 res/gui.glade:219
188211 msgid "Delete"
189212 msgstr "Elimina"
190213
192215 msgid "Download Selection"
193216 msgstr "Descarrega la selecció"
194217
195 #: res/gui.glade:219
218 #: res/gui.glade:255
196219 msgid "GNU/Linux transfer application for Elektron devices"
197220 msgstr "Aplicació GNU/Linux de transferència per a dispositius Elektron"
198221
199 #: res/gui.glade:222
222 #: res/gui.glade:258
200223 msgid "translator-credits"
201224 msgstr "David García Goñi <dagargo@gmail.com>"
202225
203 #: res/gui.glade:270
226 #: res/gui.glade:306
204227 msgid "_Receive SysEx"
205228 msgstr "_Rep SysEx"
206229
207 #: res/gui.glade:283
230 #: res/gui.glade:319
208231 msgid "_Send SysEx"
209232 msgstr "_Envia SysEx"
210233
211 #: res/gui.glade:307
234 #: res/gui.glade:343
212235 msgid "OS _Upgrade"
213236 msgstr "_Actualitza el SO"
214237
215 #: res/gui.glade:331
238 #: res/gui.glade:367
216239 msgid "_About"
217240 msgstr "_Quant a"
218241
219 #: res/gui.glade:415 res/gui.glade:585
242 #: res/gui.glade:447
243 msgid "Refresh Devices"
244 msgstr "Actualitza els dispositius"
245
246 #: res/gui.glade:551 res/gui.glade:767
220247 msgid "Go to Parent Directory"
221248 msgstr "Ves al directori pare"
222249
223 #: res/gui.glade:457 res/gui.glade:627
250 #: res/gui.glade:593 res/gui.glade:809
224251 msgid "Refresh Directory"
225252 msgstr "Actualitza el directori"
226253
227 #: res/gui.glade:514 res/gui.glade:694 res/gui.glade:1377
254 #: res/gui.glade:664 res/gui.glade:870 res/gui.glade:1662
228255 msgid "Name"
229256 msgstr "Nom"
230257
231 #: res/gui.glade:528 res/gui.glade:708
258 #: res/gui.glade:678 res/gui.glade:884
232259 msgid "Size"
233260 msgstr "Mida"
234261
235 #: res/gui.glade:761
236 msgid "Refresh Devices"
237 msgstr "Actualitza els dispositius"
238
239262 #. It is recommended to split the text in two lines if it is too long
240 #: res/gui.glade:879
263 #: res/gui.glade:987
241264 msgid "Auto play"
242265 msgstr ""
243 "Reproducció\n"
244 "automàtica"
245
246 #: res/gui.glade:1101
266 "Reproduïx\n"
267 "automàticament"
268
269 #: res/gui.glade:1027
270 msgid "Playing mix depends on the destination channels"
271 msgstr "La mescla per a reproducció depén dels canals de destinació"
272
273 #. It is recommended to split the text in two lines if it is too long
274 #: res/gui.glade:1029
275 msgid ""
276 "Mix depending\n"
277 "on destination"
278 msgstr ""
279 "Mescla segón\n"
280 "la destinació"
281
282 #: res/gui.glade:1219
283 msgid "Samples"
284 msgstr "Mostres"
285
286 #: res/gui.glade:1233
287 msgid "Channels"
288 msgstr "Canals"
289
290 #: res/gui.glade:1247
291 msgid "Sample rate"
292 msgstr "Freqüència"
293
294 #: res/gui.glade:1261
295 msgid "Bit depth"
296 msgstr "Bits"
297
298 #: res/gui.glade:1319
299 msgid "Duration"
300 msgstr "Duració"
301
302 #: res/gui.glade:1385
247303 msgid "Status"
248304 msgstr "Estat"
249305
250 #: res/gui.glade:1112
306 #: res/gui.glade:1396
251307 msgid "Type"
252308 msgstr "Tipus"
253309
254 #: res/gui.glade:1133
310 #: res/gui.glade:1417
255311 msgid "Source"
256312 msgstr "Origen"
257313
258 #: res/gui.glade:1147
314 #: res/gui.glade:1431
259315 msgid "Destination"
260316 msgstr "Destinació"
261317
262 #: res/gui.glade:1162
318 #: res/gui.glade:1446
263319 msgid "Progress"
264320 msgstr "Progrés"
265321
266 #: res/gui.glade:1194
322 #: res/gui.glade:1478
267323 msgid "Cancel Tasks"
268324 msgstr "Cancel·la les tasques"
269325
270 #: res/gui.glade:1215
326 #: res/gui.glade:1499
271327 msgid "Remove Queued Tasks"
272328 msgstr "Elimina les tasques de la cua"
273329
274 #: res/gui.glade:1236
330 #: res/gui.glade:1520
275331 msgid "Clear Finished Tasks"
276332 msgstr "Neteja les tasques terminadas"
+230
-174
po/de.po less more
00 # German translations for Elektroid package.
1 # Copyright (C) 2020 Dennis Braun
1 # Copyright (C) 2020-2022 Dennis Braun
22 # This file is distributed under the same license as the Elektroid package.
3 # Dennis Braun <d_braun@kabelmail.de>, 2020.
3 # Dennis Braun <d_braun@kabelmail.de>, 2022.
44 #
55 msgid ""
66 msgstr ""
7 "Project-Id-Version: elektroid 1.4\n"
7 "Project-Id-Version: elektroid 2.2\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2022-06-03 08:47+0200\n"
10 "PO-Revision-Date: 2021-01-11 22:00+0100\n"
9 "POT-Creation-Date: 2022-10-30 20:46+0100\n"
10 "PO-Revision-Date: 2022-11-01 21:47+0100\n"
1111 "Last-Translator: Dennis Braun <d_braun@kabelmail.de>\n"
1212 "Language-Team: German\n"
1313 "Language: de\n"
1616 "Content-Transfer-Encoding: 8bit\n"
1717 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
1818
19 #: src/elektroid.c:246
20 msgid "Samples"
21 msgstr "Samples"
22
23 #: src/elektroid.c:248
24 msgid "Presets"
25 msgstr "Presets"
26
27 #: src/elektroid.c:250
28 msgid "Projects"
29 msgstr "Projekte"
30
31 #: src/elektroid.c:252
32 msgid "Sounds"
33 msgstr "Sounds"
34
35 #: src/elektroid.c:254 src/elektroid.c:1689 src/elektroid.c:1703
19 #: src/connector.c:41 src/connector.c:47
20 msgid "MIDI device"
21 msgstr "MIDI Gerät"
22
23 #: src/elektroid.c:526 src/elektroid.c:3952
24 msgid "Not connected"
25 msgstr "Nicht verbunden"
26
27 #: src/elektroid.c:676
28 msgid "Cancelling..."
29 msgstr "Abbrechen..."
30
31 #: src/elektroid.c:697 src/elektroid.c:2497 src/elektroid.c:2706
32 #: src/elektroid.c:3362
33 msgid "Waiting..."
34 msgstr "Warte..."
35
36 #: src/elektroid.c:700
37 msgid "Sending..."
38 msgstr "Sende..."
39
40 #: src/elektroid.c:703
41 msgid "Receiving..."
42 msgstr "Empfange..."
43
44 #: src/elektroid.c:763
45 msgid "Receive SysEx"
46 msgstr "Empfange SysEx"
47
48 #: src/elektroid.c:795
49 msgid "Save SysEx"
50 msgstr "Speichere SysEx"
51
52 #: src/elektroid.c:798 src/elektroid.c:928 src/elektroid.c:1160
53 #: res/gui.glade:1617 res/gui.glade:1717
54 msgid "_Cancel"
55 msgstr "_Abbrechen"
56
57 #: src/elektroid.c:800 res/gui.glade:1631
58 msgid "_Save"
59 msgstr "_Speichern"
60
61 #: src/elektroid.c:804
62 msgid "Received SysEx"
63 msgstr "SysEx empfangen"
64
65 #: src/elektroid.c:809 src/elektroid.c:934
66 msgid "SysEx Files"
67 msgstr "SysEx Dateien"
68
69 #: src/elektroid.c:843
70 #, c-format
71 msgid "Error while saving “%s”: %s."
72 msgstr "Fehler beim Löschen »%s«: %s."
73
74 #: src/elektroid.c:864
75 #, c-format
76 msgid "Error while loading “%s”: %s."
77 msgstr "Fehler beim Löschen »%s«: %s."
78
79 #: src/elektroid.c:925
80 msgid "Open SysEx"
81 msgstr "Öffne SysEx"
82
83 #: src/elektroid.c:930
84 msgid "_Open"
85 msgstr "_Öffnen"
86
87 #: src/elektroid.c:946
88 msgid "Sending SysEx"
89 msgstr "Sende SysEx"
90
91 #: src/elektroid.c:1021
92 msgid "minutes"
93 msgstr "Minuten"
94
95 #: src/elektroid.c:1159
96 msgid "Are you sure you want to delete the selected items?"
97 msgstr "Bist du sicher das du die ausgewählten Elemente löschen möchtest?"
98
99 #: src/elektroid.c:1161
100 msgid "_Delete"
101 msgstr "_Löschen"
102
103 #: src/elektroid.c:1178
104 msgid "Deleting Files"
105 msgstr "Entfernt Dateien"
106
107 #: src/elektroid.c:1179
108 msgid "Deleting..."
109 msgstr "Lösche..."
110
111 #: src/elektroid.c:1212 res/gui.glade:121 res/gui.glade:210
112 msgid "Rename"
113 msgstr "Umbenennen"
114
115 #: src/elektroid.c:1228
116 #, c-format
117 msgid "Error while renaming to “%s”: %s."
118 msgstr "Fehler beim Umbenennen von »%s«: %s."
119
120 #: src/elektroid.c:1907 res/gui.glade:572 res/gui.glade:788
121 msgid "Add Directory"
122 msgstr "Verzeichnis hinzufügen"
123
124 #: src/elektroid.c:1925
125 #, c-format
126 msgid "Error while creating dir “%s”: %s."
127 msgstr "Fehler beim Erstellen des Verzeichnisses »%s«: %s."
128
129 #: src/elektroid.c:1997
130 msgid "Queued"
131 msgstr "In der Warteschlange"
132
133 #: src/elektroid.c:1999
134 msgid "Running"
135 msgstr "Wird ausgeführt"
136
137 #: src/elektroid.c:2001
138 msgid "Completed"
139 msgstr "Fertig"
140
141 #: src/elektroid.c:2003
142 msgid "Completed with errors"
143 msgstr "Abgeschlossen mit Fehlern"
144
145 #: src/elektroid.c:2005
146 msgid "Canceled"
147 msgstr "Abgebrochen"
148
149 #: src/elektroid.c:2007 src/elektroid.c:2021
36150 msgid "Undefined"
37151 msgstr "Undefiniert"
38152
39 #: src/elektroid.c:434
40 #, c-format
41 msgid "Connected to %s%s"
42 msgstr "Verbunden mit %s%s"
43
44 #: src/elektroid.c:442 src/elektroid.c:3256
45 msgid "Not connected"
46 msgstr "Nicht verbunden"
47
48 #: src/elektroid.c:585
49 msgid "Waiting..."
50 msgstr "Warte..."
51
52 #: src/elektroid.c:588
53 msgid "Sending..."
54 msgstr "Sende..."
55
56 #: src/elektroid.c:592
57 msgid "Receiving..."
58 msgstr "Empfange..."
59
60 #: src/elektroid.c:660
61 msgid "Receive SysEx"
62 msgstr "Empfange SysEx"
63
64 #: src/elektroid.c:684
65 msgid "Save SysEx"
66 msgstr "Speichere SysEx"
67
68 #: src/elektroid.c:687 src/elektroid.c:783 src/elektroid.c:951
69 #: res/gui.glade:1332 res/gui.glade:1432
70 msgid "_Cancel"
71 msgstr "_Abbrechen"
72
73 #: src/elektroid.c:689 res/gui.glade:1346
74 msgid "_Save"
75 msgstr "_Speichern"
76
77 #: src/elektroid.c:693
78 msgid "Received SysEx"
79 msgstr "SysEx empfangen"
80
81 #: src/elektroid.c:698 src/elektroid.c:789
82 msgid "SysEx Files"
83 msgstr "SysEx Dateien"
84
85 #: src/elektroid.c:732
86 #, c-format
87 msgid "Error while saving “%s”: %s."
88 msgstr "Fehler beim Löschen »%s«: %s."
89
90 #: src/elektroid.c:780
91 msgid "Open SysEx"
92 msgstr "Öffne SysEx"
93
94 #: src/elektroid.c:785
95 msgid "_Open"
96 msgstr "_Öffnen"
97
98 #: src/elektroid.c:806
99 #, c-format
100 msgid "Error while loading “%s”: %s."
101 msgstr "Fehler beim Löschen »%s«: %s."
102
103 #: src/elektroid.c:816
104 msgid "Send SysEx"
105 msgstr "Sende SysEx"
106
107 #: src/elektroid.c:918
108 #, c-format
109 msgid "Error while deleting “%s”: %s."
110 msgstr "Fehler beim Löschen »%s«: %s."
111
112 #: src/elektroid.c:950
113 msgid "Are you sure you want to delete the selected items?"
114 msgstr "Bist du sicher das du die ausgewählten Elemente löschen möchtest?"
115
116 #: src/elektroid.c:952
117 msgid "_Delete"
118 msgstr "_Löschen"
119
120 #: src/elektroid.c:1005 res/gui.glade:121 res/gui.glade:174
121 msgid "Rename"
122 msgstr "Umbenennen"
123
124 #: src/elektroid.c:1023
125 #, c-format
126 msgid "Error while renaming to “%s”: %s."
127 msgstr "Fehler beim Umbenennen von »%s«: %s."
128
129 #: src/elektroid.c:1589 res/gui.glade:436 res/gui.glade:606
130 msgid "Add Directory"
131 msgstr "Verzeichnis hinzufügen"
132
133 #: src/elektroid.c:1607
134 #, c-format
135 msgid "Error while creating dir “%s”: %s."
136 msgstr "Fehler beim Erstellen des Verzeichnisses »%s«: %s."
137
138 #: src/elektroid.c:1679
139 msgid "Queued"
140 msgstr "In der Warteschlange"
141
142 #: src/elektroid.c:1681
143 msgid "Running"
144 msgstr "Wird ausgeführt"
145
146 #: src/elektroid.c:1683
147 msgid "Completed"
148 msgstr "Fertig"
149
150 #: src/elektroid.c:1685
151 msgid "Completed with errors"
152 msgstr "Abgeschlossen mit Fehlern"
153
154 #: src/elektroid.c:1687
155 msgid "Canceled"
156 msgstr "Abgebrochen"
157
158 #: src/elektroid.c:1699
153 #: src/elektroid.c:2017
159154 msgid "Upload"
160155 msgstr "Hochladen"
161156
162 #: src/elektroid.c:1701
157 #: src/elektroid.c:2019
163158 msgid "Download"
164159 msgstr "Herunterladen"
165160
166 #: src/elektroid.c:2560 src/elektroid.c:2601
167 #, c-format
168 msgid "Error while moving from “%s” to “%s”: %s."
169 msgstr "Fehler beim Verschieben von »%s« nach »%s«: %s."
161 #: src/elektroid.c:2496 src/elektroid.c:2705 src/elektroid.c:3361
162 msgid "Preparing Tasks"
163 msgstr "Aufgaben werden vorbereitet"
164
165 #: src/elektroid.c:3077
166 msgid "Connecting to Device"
167 msgstr "Verbindung zum Gerät wird hergestellt"
168
169 #: src/elektroid.c:3078
170 msgid "Connecting..."
171 msgstr "Verbinde..."
172
173 #: src/elektroid.c:3088
174 #, c-format
175 msgid "Device “%s” not recognized: %s"
176 msgstr "Gerät “%s” nicht erkannt: %s"
177
178 #: src/elektroid.c:3355
179 msgid "Moving Files"
180 msgstr "Verschiebe Dateien"
181
182 #: src/elektroid.c:3356
183 msgid "Moving..."
184 msgstr "Verschiebe..."
185
186 #: src/local.c:492
187 msgid "System"
188 msgstr ""
189
190 #: src/connectors/sds.c:1127 src/connectors/sds.c:1133
191 msgid "SDS sampler"
192 msgstr ""
170193
171194 #: res/gui.glade:70
172195 msgid "Upload Selection"
173196 msgstr "Upload Auswahl"
174197
175 #: res/gui.glade:85
198 #: res/gui.glade:85 res/gui.glade:174
176199 msgid "Play"
177200 msgstr "Abspielen"
178201
179 #: res/gui.glade:99
202 #: res/gui.glade:99 res/gui.glade:188
180203 msgid "Open With External Editor"
181204 msgstr "Öffnen mit externen Editor"
182205
183 #: res/gui.glade:107
206 #: res/gui.glade:107 res/gui.glade:196
184207 msgid "Show in File Manager"
185208 msgstr "Im Dateimanager _Anzeigen"
186209
187 #: res/gui.glade:130 res/gui.glade:183
210 #: res/gui.glade:130 res/gui.glade:219
188211 msgid "Delete"
189212 msgstr "Löschen"
190213
192215 msgid "Download Selection"
193216 msgstr "Download Auswahl"
194217
195 #: res/gui.glade:219
218 #: res/gui.glade:255
196219 msgid "GNU/Linux transfer application for Elektron devices"
197220 msgstr "GNU/Linux Transfer Anwendung für Elektron Instrumente"
198221
199 #: res/gui.glade:222
222 #: res/gui.glade:258
200223 msgid "translator-credits"
201224 msgstr "Dennis Braun <d_braun@kabelmail.de>"
202225
203 #: res/gui.glade:270
226 #: res/gui.glade:306
204227 msgid "_Receive SysEx"
205228 msgstr "_Empfange SysEx"
206229
207 #: res/gui.glade:283
230 #: res/gui.glade:319
208231 msgid "_Send SysEx"
209232 msgstr "_Sende SysEx"
210233
211 #: res/gui.glade:307
234 #: res/gui.glade:343
212235 msgid "OS _Upgrade"
213236 msgstr "OS _Aktualisierung"
214237
215 #: res/gui.glade:331
238 #: res/gui.glade:367
216239 msgid "_About"
217240 msgstr "_Info"
218241
219 #: res/gui.glade:415 res/gui.glade:585
242 #: res/gui.glade:447
243 msgid "Refresh Devices"
244 msgstr "Aktualisiere Geräte"
245
246 #: res/gui.glade:551 res/gui.glade:767
220247 msgid "Go to Parent Directory"
221248 msgstr "Gehe zum Überverzeichnis"
222249
223 #: res/gui.glade:457 res/gui.glade:627
250 #: res/gui.glade:593 res/gui.glade:809
224251 msgid "Refresh Directory"
225252 msgstr "Aktualisiere Verzeichnis"
226253
227 #: res/gui.glade:514 res/gui.glade:694 res/gui.glade:1377
254 #: res/gui.glade:664 res/gui.glade:870 res/gui.glade:1662
228255 msgid "Name"
229256 msgstr "Name"
230257
231 #: res/gui.glade:528 res/gui.glade:708
258 #: res/gui.glade:678 res/gui.glade:884
232259 msgid "Size"
233260 msgstr "Größe"
234261
235 #: res/gui.glade:761
236 msgid "Refresh Devices"
237 msgstr "Aktualisiere Geräte"
238
239262 #. It is recommended to split the text in two lines if it is too long
240 #: res/gui.glade:879
263 #: res/gui.glade:987
241264 msgid "Auto play"
242265 msgstr "Auto Play"
243266
244 #: res/gui.glade:1101
267 #: res/gui.glade:1027
268 msgid "Playing mix depends on the destination channels"
269 msgstr "Das Abspielen vom Mix hängt von den Zielkanälen ab"
270
271 #. It is recommended to split the text in two lines if it is too long
272 #: res/gui.glade:1029
273 msgid ""
274 "Mix depending\n"
275 "on destination"
276 msgstr ""
277 "Mix hängt ab von\n"
278 "den Zielkanälen"
279
280 #: res/gui.glade:1219
281 msgid "Samples"
282 msgstr ""
283
284 #: res/gui.glade:1233
285 msgid "Channels"
286 msgstr "Kanäle"
287
288 #: res/gui.glade:1247
289 msgid "Sample rate"
290 msgstr "Sample Rate"
291
292 #: res/gui.glade:1261
293 msgid "Bit depth"
294 msgstr "Bit-Tiefe"
295
296 #: res/gui.glade:1319
297 msgid "Duration"
298 msgstr "Dauer"
299
300 #: res/gui.glade:1385
245301 msgid "Status"
246302 msgstr "Status"
247303
248 #: res/gui.glade:1112
304 #: res/gui.glade:1396
249305 msgid "Type"
250306 msgstr "Typ"
251307
252 #: res/gui.glade:1133
308 #: res/gui.glade:1417
253309 msgid "Source"
254310 msgstr "Quelle"
255311
256 #: res/gui.glade:1147
312 #: res/gui.glade:1431
257313 msgid "Destination"
258314 msgstr "Ziel"
259315
260 #: res/gui.glade:1162
316 #: res/gui.glade:1446
261317 msgid "Progress"
262318 msgstr "Fortschritt"
263319
264 #: res/gui.glade:1194
320 #: res/gui.glade:1478
265321 msgid "Cancel Tasks"
266322 msgstr "Aufgaben abbrechen"
267323
268 #: res/gui.glade:1215
324 #: res/gui.glade:1499
269325 msgid "Remove Queued Tasks"
270326 msgstr "Lösche Aufgaben in der Warteschlange"
271327
272 #: res/gui.glade:1236
328 #: res/gui.glade:1520
273329 msgid "Clear Finished Tasks"
274330 msgstr "Abgeschlossene Aufgaben aufräumen"
55 #, fuzzy
66 msgid ""
77 msgstr ""
8 "Project-Id-Version: elektroid 2.1\n"
8 "Project-Id-Version: elektroid 2.2\n"
99 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
10 "POT-Creation-Date: 2022-06-03 08:47+0200\n"
10 "POT-Creation-Date: 2022-10-30 20:46+0100\n"
1111 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1212 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313 "Language-Team: LANGUAGE <LL@li.org>\n"
1616 "Content-Type: text/plain; charset=UTF-8\n"
1717 "Content-Transfer-Encoding: 8bit\n"
1818
19 #: src/elektroid.c:246
20 msgid "Samples"
21 msgstr ""
22
23 #: src/elektroid.c:248
24 msgid "Presets"
25 msgstr ""
26
27 #: src/elektroid.c:250
28 msgid "Projects"
29 msgstr ""
30
31 #: src/elektroid.c:252
32 msgid "Sounds"
33 msgstr ""
34
35 #: src/elektroid.c:254 src/elektroid.c:1689 src/elektroid.c:1703
19 #: src/connector.c:41 src/connector.c:47
20 msgid "MIDI device"
21 msgstr ""
22
23 #: src/elektroid.c:526 src/elektroid.c:3952
24 msgid "Not connected"
25 msgstr ""
26
27 #: src/elektroid.c:676
28 msgid "Cancelling..."
29 msgstr ""
30
31 #: src/elektroid.c:697 src/elektroid.c:2497 src/elektroid.c:2706
32 #: src/elektroid.c:3362
33 msgid "Waiting..."
34 msgstr ""
35
36 #: src/elektroid.c:700
37 msgid "Sending..."
38 msgstr ""
39
40 #: src/elektroid.c:703
41 msgid "Receiving..."
42 msgstr ""
43
44 #: src/elektroid.c:763
45 msgid "Receive SysEx"
46 msgstr ""
47
48 #: src/elektroid.c:795
49 msgid "Save SysEx"
50 msgstr ""
51
52 #: src/elektroid.c:798 src/elektroid.c:928 src/elektroid.c:1160
53 #: res/gui.glade:1617 res/gui.glade:1717
54 msgid "_Cancel"
55 msgstr ""
56
57 #: src/elektroid.c:800 res/gui.glade:1631
58 msgid "_Save"
59 msgstr ""
60
61 #: src/elektroid.c:804
62 msgid "Received SysEx"
63 msgstr ""
64
65 #: src/elektroid.c:809 src/elektroid.c:934
66 msgid "SysEx Files"
67 msgstr ""
68
69 #: src/elektroid.c:843
70 #, c-format
71 msgid "Error while saving “%s”: %s."
72 msgstr ""
73
74 #: src/elektroid.c:864
75 #, c-format
76 msgid "Error while loading “%s”: %s."
77 msgstr ""
78
79 #: src/elektroid.c:925
80 msgid "Open SysEx"
81 msgstr ""
82
83 #: src/elektroid.c:930
84 msgid "_Open"
85 msgstr ""
86
87 #: src/elektroid.c:946
88 msgid "Sending SysEx"
89 msgstr ""
90
91 #: src/elektroid.c:1021
92 msgid "minutes"
93 msgstr ""
94
95 #: src/elektroid.c:1159
96 msgid "Are you sure you want to delete the selected items?"
97 msgstr ""
98
99 #: src/elektroid.c:1161
100 msgid "_Delete"
101 msgstr ""
102
103 #: src/elektroid.c:1178
104 msgid "Deleting Files"
105 msgstr ""
106
107 #: src/elektroid.c:1179
108 msgid "Deleting..."
109 msgstr ""
110
111 #: src/elektroid.c:1212 res/gui.glade:121 res/gui.glade:210
112 msgid "Rename"
113 msgstr ""
114
115 #: src/elektroid.c:1228
116 #, c-format
117 msgid "Error while renaming to “%s”: %s."
118 msgstr ""
119
120 #: src/elektroid.c:1907 res/gui.glade:572 res/gui.glade:788
121 msgid "Add Directory"
122 msgstr ""
123
124 #: src/elektroid.c:1925
125 #, c-format
126 msgid "Error while creating dir “%s”: %s."
127 msgstr ""
128
129 #: src/elektroid.c:1997
130 msgid "Queued"
131 msgstr ""
132
133 #: src/elektroid.c:1999
134 msgid "Running"
135 msgstr ""
136
137 #: src/elektroid.c:2001
138 msgid "Completed"
139 msgstr ""
140
141 #: src/elektroid.c:2003
142 msgid "Completed with errors"
143 msgstr ""
144
145 #: src/elektroid.c:2005
146 msgid "Canceled"
147 msgstr ""
148
149 #: src/elektroid.c:2007 src/elektroid.c:2021
36150 msgid "Undefined"
37151 msgstr ""
38152
39 #: src/elektroid.c:434
40 #, c-format
41 msgid "Connected to %s%s"
42 msgstr ""
43
44 #: src/elektroid.c:442 src/elektroid.c:3256
45 msgid "Not connected"
46 msgstr ""
47
48 #: src/elektroid.c:585
49 msgid "Waiting..."
50 msgstr ""
51
52 #: src/elektroid.c:588
53 msgid "Sending..."
54 msgstr ""
55
56 #: src/elektroid.c:592
57 msgid "Receiving..."
58 msgstr ""
59
60 #: src/elektroid.c:660
61 msgid "Receive SysEx"
62 msgstr ""
63
64 #: src/elektroid.c:684
65 msgid "Save SysEx"
66 msgstr ""
67
68 #: src/elektroid.c:687 src/elektroid.c:783 src/elektroid.c:951
69 #: res/gui.glade:1332 res/gui.glade:1432
70 msgid "_Cancel"
71 msgstr ""
72
73 #: src/elektroid.c:689 res/gui.glade:1346
74 msgid "_Save"
75 msgstr ""
76
77 #: src/elektroid.c:693
78 msgid "Received SysEx"
79 msgstr ""
80
81 #: src/elektroid.c:698 src/elektroid.c:789
82 msgid "SysEx Files"
83 msgstr ""
84
85 #: src/elektroid.c:732
86 #, c-format
87 msgid "Error while saving “%s”: %s."
88 msgstr ""
89
90 #: src/elektroid.c:780
91 msgid "Open SysEx"
92 msgstr ""
93
94 #: src/elektroid.c:785
95 msgid "_Open"
96 msgstr ""
97
98 #: src/elektroid.c:806
99 #, c-format
100 msgid "Error while loading “%s”: %s."
101 msgstr ""
102
103 #: src/elektroid.c:816
104 msgid "Send SysEx"
105 msgstr ""
106
107 #: src/elektroid.c:918
108 #, c-format
109 msgid "Error while deleting “%s”: %s."
110 msgstr ""
111
112 #: src/elektroid.c:950
113 msgid "Are you sure you want to delete the selected items?"
114 msgstr ""
115
116 #: src/elektroid.c:952
117 msgid "_Delete"
118 msgstr ""
119
120 #: src/elektroid.c:1005 res/gui.glade:121 res/gui.glade:174
121 msgid "Rename"
122 msgstr ""
123
124 #: src/elektroid.c:1023
125 #, c-format
126 msgid "Error while renaming to “%s”: %s."
127 msgstr ""
128
129 #: src/elektroid.c:1589 res/gui.glade:436 res/gui.glade:606
130 msgid "Add Directory"
131 msgstr ""
132
133 #: src/elektroid.c:1607
134 #, c-format
135 msgid "Error while creating dir “%s”: %s."
136 msgstr ""
137
138 #: src/elektroid.c:1679
139 msgid "Queued"
140 msgstr ""
141
142 #: src/elektroid.c:1681
143 msgid "Running"
144 msgstr ""
145
146 #: src/elektroid.c:1683
147 msgid "Completed"
148 msgstr ""
149
150 #: src/elektroid.c:1685
151 msgid "Completed with errors"
152 msgstr ""
153
154 #: src/elektroid.c:1687
155 msgid "Canceled"
156 msgstr ""
157
158 #: src/elektroid.c:1699
153 #: src/elektroid.c:2017
159154 msgid "Upload"
160155 msgstr ""
161156
162 #: src/elektroid.c:1701
157 #: src/elektroid.c:2019
163158 msgid "Download"
164159 msgstr ""
165160
166 #: src/elektroid.c:2560 src/elektroid.c:2601
167 #, c-format
168 msgid "Error while moving from “%s” to “%s”: %s."
161 #: src/elektroid.c:2496 src/elektroid.c:2705 src/elektroid.c:3361
162 msgid "Preparing Tasks"
163 msgstr ""
164
165 #: src/elektroid.c:3077
166 msgid "Connecting to Device"
167 msgstr ""
168
169 #: src/elektroid.c:3078
170 msgid "Connecting..."
171 msgstr ""
172
173 #: src/elektroid.c:3088
174 #, c-format
175 msgid "Device “%s” not recognized: %s"
176 msgstr ""
177
178 #: src/elektroid.c:3355
179 msgid "Moving Files"
180 msgstr ""
181
182 #: src/elektroid.c:3356
183 msgid "Moving..."
184 msgstr ""
185
186 #: src/local.c:492
187 msgid "System"
188 msgstr ""
189
190 #: src/connectors/sds.c:1127 src/connectors/sds.c:1133
191 msgid "SDS sampler"
169192 msgstr ""
170193
171194 #: res/gui.glade:70
172195 msgid "Upload Selection"
173196 msgstr ""
174197
175 #: res/gui.glade:85
198 #: res/gui.glade:85 res/gui.glade:174
176199 msgid "Play"
177200 msgstr ""
178201
179 #: res/gui.glade:99
202 #: res/gui.glade:99 res/gui.glade:188
180203 msgid "Open With External Editor"
181204 msgstr ""
182205
183 #: res/gui.glade:107
206 #: res/gui.glade:107 res/gui.glade:196
184207 msgid "Show in File Manager"
185208 msgstr ""
186209
187 #: res/gui.glade:130 res/gui.glade:183
210 #: res/gui.glade:130 res/gui.glade:219
188211 msgid "Delete"
189212 msgstr ""
190213
192215 msgid "Download Selection"
193216 msgstr ""
194217
195 #: res/gui.glade:219
218 #: res/gui.glade:255
196219 msgid "GNU/Linux transfer application for Elektron devices"
197220 msgstr ""
198221
199 #: res/gui.glade:222
222 #: res/gui.glade:258
200223 msgid "translator-credits"
201224 msgstr ""
202225
203 #: res/gui.glade:270
226 #: res/gui.glade:306
204227 msgid "_Receive SysEx"
205228 msgstr ""
206229
207 #: res/gui.glade:283
230 #: res/gui.glade:319
208231 msgid "_Send SysEx"
209232 msgstr ""
210233
211 #: res/gui.glade:307
234 #: res/gui.glade:343
212235 msgid "OS _Upgrade"
213236 msgstr ""
214237
215 #: res/gui.glade:331
238 #: res/gui.glade:367
216239 msgid "_About"
217240 msgstr ""
218241
219 #: res/gui.glade:415 res/gui.glade:585
242 #: res/gui.glade:447
243 msgid "Refresh Devices"
244 msgstr ""
245
246 #: res/gui.glade:551 res/gui.glade:767
220247 msgid "Go to Parent Directory"
221248 msgstr ""
222249
223 #: res/gui.glade:457 res/gui.glade:627
250 #: res/gui.glade:593 res/gui.glade:809
224251 msgid "Refresh Directory"
225252 msgstr ""
226253
227 #: res/gui.glade:514 res/gui.glade:694 res/gui.glade:1377
254 #: res/gui.glade:664 res/gui.glade:870 res/gui.glade:1662
228255 msgid "Name"
229256 msgstr ""
230257
231 #: res/gui.glade:528 res/gui.glade:708
258 #: res/gui.glade:678 res/gui.glade:884
232259 msgid "Size"
233260 msgstr ""
234261
235 #: res/gui.glade:761
236 msgid "Refresh Devices"
237 msgstr ""
238
239262 #. It is recommended to split the text in two lines if it is too long
240 #: res/gui.glade:879
263 #: res/gui.glade:987
241264 msgid "Auto play"
242265 msgstr ""
243266
244 #: res/gui.glade:1101
267 #: res/gui.glade:1027
268 msgid "Playing mix depends on the destination channels"
269 msgstr ""
270
271 #. It is recommended to split the text in two lines if it is too long
272 #: res/gui.glade:1029
273 msgid ""
274 "Mix depending\n"
275 "on destination"
276 msgstr ""
277
278 #: res/gui.glade:1219
279 msgid "Samples"
280 msgstr ""
281
282 #: res/gui.glade:1233
283 msgid "Channels"
284 msgstr ""
285
286 #: res/gui.glade:1247
287 msgid "Sample rate"
288 msgstr ""
289
290 #: res/gui.glade:1261
291 msgid "Bit depth"
292 msgstr ""
293
294 #: res/gui.glade:1319
295 msgid "Duration"
296 msgstr ""
297
298 #: res/gui.glade:1385
245299 msgid "Status"
246300 msgstr ""
247301
248 #: res/gui.glade:1112
302 #: res/gui.glade:1396
249303 msgid "Type"
250304 msgstr ""
251305
252 #: res/gui.glade:1133
306 #: res/gui.glade:1417
253307 msgid "Source"
254308 msgstr ""
255309
256 #: res/gui.glade:1147
310 #: res/gui.glade:1431
257311 msgid "Destination"
258312 msgstr ""
259313
260 #: res/gui.glade:1162
314 #: res/gui.glade:1446
261315 msgid "Progress"
262316 msgstr ""
263317
264 #: res/gui.glade:1194
318 #: res/gui.glade:1478
265319 msgid "Cancel Tasks"
266320 msgstr ""
267321
268 #: res/gui.glade:1215
322 #: res/gui.glade:1499
269323 msgid "Remove Queued Tasks"
270324 msgstr ""
271325
272 #: res/gui.glade:1236
326 #: res/gui.glade:1520
273327 msgid "Clear Finished Tasks"
274328 msgstr ""
+227
-171
po/en.po less more
44 #
55 msgid ""
66 msgstr ""
7 "Project-Id-Version: elektroid 1.4\n"
7 "Project-Id-Version: elektroid 2.2\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2022-06-03 08:47+0200\n"
9 "POT-Creation-Date: 2022-10-30 20:46+0100\n"
1010 "PO-Revision-Date: 2020-04-26 13:00+0100\n"
1111 "Last-Translator: David García Goñi <dagargo@gmail.com>\n"
1212 "Language-Team: English\n"
1616 "Content-Transfer-Encoding: 8bit\n"
1717 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1818
19 #: src/elektroid.c:246
20 msgid "Samples"
21 msgstr "Samples"
22
23 #: src/elektroid.c:248
24 msgid "Presets"
25 msgstr "Presets"
26
27 #: src/elektroid.c:250
28 msgid "Projects"
29 msgstr "Projects"
30
31 #: src/elektroid.c:252
32 msgid "Sounds"
33 msgstr "Sounds"
34
35 #: src/elektroid.c:254 src/elektroid.c:1689 src/elektroid.c:1703
19 #: src/connector.c:41 src/connector.c:47
20 msgid "MIDI device"
21 msgstr "MIDI device"
22
23 #: src/elektroid.c:526 src/elektroid.c:3952
24 msgid "Not connected"
25 msgstr "Not connected"
26
27 #: src/elektroid.c:676
28 msgid "Cancelling..."
29 msgstr "Cancelling..."
30
31 #: src/elektroid.c:697 src/elektroid.c:2497 src/elektroid.c:2706
32 #: src/elektroid.c:3362
33 msgid "Waiting..."
34 msgstr "Waiting..."
35
36 #: src/elektroid.c:700
37 msgid "Sending..."
38 msgstr "Sending..."
39
40 #: src/elektroid.c:703
41 msgid "Receiving..."
42 msgstr "Receiving..."
43
44 #: src/elektroid.c:763
45 msgid "Receive SysEx"
46 msgstr "Receive SysEx"
47
48 #: src/elektroid.c:795
49 msgid "Save SysEx"
50 msgstr "Save SysEx"
51
52 #: src/elektroid.c:798 src/elektroid.c:928 src/elektroid.c:1160
53 #: res/gui.glade:1617 res/gui.glade:1717
54 msgid "_Cancel"
55 msgstr "_Cancel"
56
57 #: src/elektroid.c:800 res/gui.glade:1631
58 msgid "_Save"
59 msgstr "_Save"
60
61 #: src/elektroid.c:804
62 msgid "Received SysEx"
63 msgstr "Received SysEx"
64
65 #: src/elektroid.c:809 src/elektroid.c:934
66 msgid "SysEx Files"
67 msgstr "SysEx Files"
68
69 #: src/elektroid.c:843
70 #, c-format
71 msgid "Error while saving “%s”: %s."
72 msgstr "Error while saving “%s”: %s."
73
74 #: src/elektroid.c:864
75 #, c-format
76 msgid "Error while loading “%s”: %s."
77 msgstr "Error while loading “%s”: %s."
78
79 #: src/elektroid.c:925
80 msgid "Open SysEx"
81 msgstr "Open SysEx"
82
83 #: src/elektroid.c:930
84 msgid "_Open"
85 msgstr "_Open"
86
87 #: src/elektroid.c:946
88 msgid "Sending SysEx"
89 msgstr "Sending SysEx"
90
91 #: src/elektroid.c:1021
92 msgid "minutes"
93 msgstr "minutes"
94
95 #: src/elektroid.c:1159
96 msgid "Are you sure you want to delete the selected items?"
97 msgstr "Are you sure you want to delete the selected items?"
98
99 #: src/elektroid.c:1161
100 msgid "_Delete"
101 msgstr "_Delete"
102
103 #: src/elektroid.c:1178
104 msgid "Deleting Files"
105 msgstr "Deleting Files"
106
107 #: src/elektroid.c:1179
108 msgid "Deleting..."
109 msgstr "Deleting..."
110
111 #: src/elektroid.c:1212 res/gui.glade:121 res/gui.glade:210
112 msgid "Rename"
113 msgstr "Rename"
114
115 #: src/elektroid.c:1228
116 #, c-format
117 msgid "Error while renaming to “%s”: %s."
118 msgstr "Error while renaming to “%s”: %s."
119
120 #: src/elektroid.c:1907 res/gui.glade:572 res/gui.glade:788
121 msgid "Add Directory"
122 msgstr "Add Directory"
123
124 #: src/elektroid.c:1925
125 #, c-format
126 msgid "Error while creating dir “%s”: %s."
127 msgstr "Error while creating dir “%s”: %s."
128
129 #: src/elektroid.c:1997
130 msgid "Queued"
131 msgstr "Queued"
132
133 #: src/elektroid.c:1999
134 msgid "Running"
135 msgstr "Running"
136
137 #: src/elektroid.c:2001
138 msgid "Completed"
139 msgstr "Completed"
140
141 #: src/elektroid.c:2003
142 msgid "Completed with errors"
143 msgstr "Completed with errors"
144
145 #: src/elektroid.c:2005
146 msgid "Canceled"
147 msgstr "Canceled"
148
149 #: src/elektroid.c:2007 src/elektroid.c:2021
36150 msgid "Undefined"
37151 msgstr "Undefined"
38152
39 #: src/elektroid.c:434
40 #, c-format
41 msgid "Connected to %s%s"
42 msgstr "Connected to %s%s"
43
44 #: src/elektroid.c:442 src/elektroid.c:3256
45 msgid "Not connected"
46 msgstr "Not connected"
47
48 #: src/elektroid.c:585
49 msgid "Waiting..."
50 msgstr "Waiting..."
51
52 #: src/elektroid.c:588
53 msgid "Sending..."
54 msgstr "Sending..."
55
56 #: src/elektroid.c:592
57 msgid "Receiving..."
58 msgstr "Receiving..."
59
60 #: src/elektroid.c:660
61 msgid "Receive SysEx"
62 msgstr "Receive SysEx"
63
64 #: src/elektroid.c:684
65 msgid "Save SysEx"
66 msgstr "Save SysEx"
67
68 #: src/elektroid.c:687 src/elektroid.c:783 src/elektroid.c:951
69 #: res/gui.glade:1332 res/gui.glade:1432
70 msgid "_Cancel"
71 msgstr "_Cancel"
72
73 #: src/elektroid.c:689 res/gui.glade:1346
74 msgid "_Save"
75 msgstr "_Save"
76
77 #: src/elektroid.c:693
78 msgid "Received SysEx"
79 msgstr "Received SysEx"
80
81 #: src/elektroid.c:698 src/elektroid.c:789
82 msgid "SysEx Files"
83 msgstr "SysEx Files"
84
85 #: src/elektroid.c:732
86 #, c-format
87 msgid "Error while saving “%s”: %s."
88 msgstr "Error while saving “%s”: %s."
89
90 #: src/elektroid.c:780
91 msgid "Open SysEx"
92 msgstr "Open SysEx"
93
94 #: src/elektroid.c:785
95 msgid "_Open"
96 msgstr "_Open"
97
98 #: src/elektroid.c:806
99 #, c-format
100 msgid "Error while loading “%s”: %s."
101 msgstr "Error while loading “%s”: %s."
102
103 #: src/elektroid.c:816
104 msgid "Send SysEx"
105 msgstr "Send SysEx"
106
107 #: src/elektroid.c:918
108 #, c-format
109 msgid "Error while deleting “%s”: %s."
110 msgstr "Error while deleting “%s”: %s."
111
112 #: src/elektroid.c:950
113 msgid "Are you sure you want to delete the selected items?"
114 msgstr "Are you sure you want to delete the selected items?"
115
116 #: src/elektroid.c:952
117 msgid "_Delete"
118 msgstr "_Delete"
119
120 #: src/elektroid.c:1005 res/gui.glade:121 res/gui.glade:174
121 msgid "Rename"
122 msgstr "Rename"
123
124 #: src/elektroid.c:1023
125 #, c-format
126 msgid "Error while renaming to “%s”: %s."
127 msgstr "Error while renaming to “%s”: %s."
128
129 #: src/elektroid.c:1589 res/gui.glade:436 res/gui.glade:606
130 msgid "Add Directory"
131 msgstr "Add Directory"
132
133 #: src/elektroid.c:1607
134 #, c-format
135 msgid "Error while creating dir “%s”: %s."
136 msgstr "Error while creating dir “%s”: %s."
137
138 #: src/elektroid.c:1679
139 msgid "Queued"
140 msgstr "Queued"
141
142 #: src/elektroid.c:1681
143 msgid "Running"
144 msgstr "Running"
145
146 #: src/elektroid.c:1683
147 msgid "Completed"
148 msgstr "Completed"
149
150 #: src/elektroid.c:1685
151 msgid "Completed with errors"
152 msgstr "Completed with errors"
153
154 #: src/elektroid.c:1687
155 msgid "Canceled"
156 msgstr "Canceled"
157
158 #: src/elektroid.c:1699
153 #: src/elektroid.c:2017
159154 msgid "Upload"
160155 msgstr "Upload"
161156
162 #: src/elektroid.c:1701
157 #: src/elektroid.c:2019
163158 msgid "Download"
164159 msgstr "Download"
165160
166 #: src/elektroid.c:2560 src/elektroid.c:2601
167 #, c-format
168 msgid "Error while moving from “%s” to “%s”: %s."
169 msgstr "Error while moving from “%s” to “%s”: %s."
161 #: src/elektroid.c:2496 src/elektroid.c:2705 src/elektroid.c:3361
162 msgid "Preparing Tasks"
163 msgstr "Preparing Tasks"
164
165 #: src/elektroid.c:3077
166 msgid "Connecting to Device"
167 msgstr "Connecting to Device"
168
169 #: src/elektroid.c:3078
170 msgid "Connecting..."
171 msgstr "Connecting..."
172
173 #: src/elektroid.c:3088
174 #, c-format
175 msgid "Device “%s” not recognized: %s"
176 msgstr "Device “%s” not recognized: %s"
177
178 #: src/elektroid.c:3355
179 msgid "Moving Files"
180 msgstr "Moving Files"
181
182 #: src/elektroid.c:3356
183 msgid "Moving..."
184 msgstr "Moving..."
185
186 #: src/local.c:492
187 msgid "System"
188 msgstr "System"
189
190 #: src/connectors/sds.c:1127 src/connectors/sds.c:1133
191 msgid "SDS sampler"
192 msgstr "SDS sampler"
170193
171194 #: res/gui.glade:70
172195 msgid "Upload Selection"
173196 msgstr "Upload Selection"
174197
175 #: res/gui.glade:85
198 #: res/gui.glade:85 res/gui.glade:174
176199 msgid "Play"
177200 msgstr "Play"
178201
179 #: res/gui.glade:99
202 #: res/gui.glade:99 res/gui.glade:188
180203 msgid "Open With External Editor"
181204 msgstr "Open With External Editor"
182205
183 #: res/gui.glade:107
206 #: res/gui.glade:107 res/gui.glade:196
184207 msgid "Show in File Manager"
185208 msgstr "Show in File Manager"
186209
187 #: res/gui.glade:130 res/gui.glade:183
210 #: res/gui.glade:130 res/gui.glade:219
188211 msgid "Delete"
189212 msgstr "Delete"
190213
192215 msgid "Download Selection"
193216 msgstr "Download selection"
194217
195 #: res/gui.glade:219
218 #: res/gui.glade:255
196219 msgid "GNU/Linux transfer application for Elektron devices"
197220 msgstr "GNU/Linux transfer application for Elektron devices"
198221
199 #: res/gui.glade:222
222 #: res/gui.glade:258
200223 msgid "translator-credits"
201224 msgstr "David García Goñi <dagargo@gmail.com>"
202225
203 #: res/gui.glade:270
226 #: res/gui.glade:306
204227 msgid "_Receive SysEx"
205228 msgstr "_Receive SysEx"
206229
207 #: res/gui.glade:283
230 #: res/gui.glade:319
208231 msgid "_Send SysEx"
209232 msgstr "_Send SysEx"
210233
211 #: res/gui.glade:307
234 #: res/gui.glade:343
212235 msgid "OS _Upgrade"
213236 msgstr "OS _Upgrade"
214237
215 #: res/gui.glade:331
238 #: res/gui.glade:367
216239 msgid "_About"
217240 msgstr "_About"
218241
219 #: res/gui.glade:415 res/gui.glade:585
242 #: res/gui.glade:447
243 msgid "Refresh Devices"
244 msgstr "Refresh Devices"
245
246 #: res/gui.glade:551 res/gui.glade:767
220247 msgid "Go to Parent Directory"
221248 msgstr "Go to Parent Directory"
222249
223 #: res/gui.glade:457 res/gui.glade:627
250 #: res/gui.glade:593 res/gui.glade:809
224251 msgid "Refresh Directory"
225252 msgstr "Refresh Directory"
226253
227 #: res/gui.glade:514 res/gui.glade:694 res/gui.glade:1377
254 #: res/gui.glade:664 res/gui.glade:870 res/gui.glade:1662
228255 msgid "Name"
229256 msgstr "Name"
230257
231 #: res/gui.glade:528 res/gui.glade:708
258 #: res/gui.glade:678 res/gui.glade:884
232259 msgid "Size"
233260 msgstr "Size"
234261
235 #: res/gui.glade:761
236 msgid "Refresh Devices"
237 msgstr "Refresh Devices"
238
239262 #. It is recommended to split the text in two lines if it is too long
240 #: res/gui.glade:879
263 #: res/gui.glade:987
241264 msgid "Auto play"
242265 msgstr "Auto play"
243266
244 #: res/gui.glade:1101
267 #: res/gui.glade:1027
268 msgid "Playing mix depends on the destination channels"
269 msgstr "Playing mix depends on the destination channels"
270
271 #. It is recommended to split the text in two lines if it is too long
272 #: res/gui.glade:1029
273 msgid ""
274 "Mix depending\n"
275 "on destination"
276 msgstr ""
277 "Mix depending\n"
278 "on destination"
279
280 #: res/gui.glade:1219
281 msgid "Samples"
282 msgstr "Samples"
283
284 #: res/gui.glade:1233
285 msgid "Channels"
286 msgstr "Channels"
287
288 #: res/gui.glade:1247
289 msgid "Sample rate"
290 msgstr "Sample rate"
291
292 #: res/gui.glade:1261
293 msgid "Bit depth"
294 msgstr "Bit depth"
295
296 #: res/gui.glade:1319
297 msgid "Duration"
298 msgstr "Duration"
299
300 #: res/gui.glade:1385
245301 msgid "Status"
246302 msgstr "Status"
247303
248 #: res/gui.glade:1112
304 #: res/gui.glade:1396
249305 msgid "Type"
250306 msgstr "Type"
251307
252 #: res/gui.glade:1133
308 #: res/gui.glade:1417
253309 msgid "Source"
254310 msgstr "Source"
255311
256 #: res/gui.glade:1147
312 #: res/gui.glade:1431
257313 msgid "Destination"
258314 msgstr "Destination"
259315
260 #: res/gui.glade:1162
316 #: res/gui.glade:1446
261317 msgid "Progress"
262318 msgstr "Progress"
263319
264 #: res/gui.glade:1194
320 #: res/gui.glade:1478
265321 msgid "Cancel Tasks"
266322 msgstr "Cancel Tasks"
267323
268 #: res/gui.glade:1215
324 #: res/gui.glade:1499
269325 msgid "Remove Queued Tasks"
270326 msgstr "Remove Queued Tasks"
271327
272 #: res/gui.glade:1236
328 #: res/gui.glade:1520
273329 msgid "Clear Finished Tasks"
274330 msgstr "Clear Finished Tasks"
+230
-174
po/es.po less more
44 #
55 msgid ""
66 msgstr ""
7 "Project-Id-Version: elektroid 1.4\n"
7 "Project-Id-Version: elektroid 2.2\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2022-06-03 08:47+0200\n"
9 "POT-Creation-Date: 2022-10-30 20:46+0100\n"
1010 "PO-Revision-Date: 2020-04-26 13:00+0100\n"
1111 "Last-Translator: David García Goñi <dagargo@gmail.com>\n"
1212 "Language-Team: Spanish\n"
1616 "Content-Transfer-Encoding: 8bit\n"
1717 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1818
19 #: src/elektroid.c:246
20 msgid "Samples"
21 msgstr "Muestras"
22
23 #: src/elektroid.c:248
24 msgid "Presets"
25 msgstr "Programas"
26
27 #: src/elektroid.c:250
28 msgid "Projects"
29 msgstr "Proyectos"
30
31 #: src/elektroid.c:252
32 msgid "Sounds"
33 msgstr "Sonidos"
34
35 #: src/elektroid.c:254 src/elektroid.c:1689 src/elektroid.c:1703
19 #: src/connector.c:41 src/connector.c:47
20 msgid "MIDI device"
21 msgstr "Dispositivo MIDI"
22
23 #: src/elektroid.c:526 src/elektroid.c:3952
24 msgid "Not connected"
25 msgstr "No conectado"
26
27 #: src/elektroid.c:676
28 msgid "Cancelling..."
29 msgstr "Cancelando..."
30
31 #: src/elektroid.c:697 src/elektroid.c:2497 src/elektroid.c:2706
32 #: src/elektroid.c:3362
33 msgid "Waiting..."
34 msgstr "Esperando..."
35
36 #: src/elektroid.c:700
37 msgid "Sending..."
38 msgstr "Enviando..."
39
40 #: src/elektroid.c:703
41 msgid "Receiving..."
42 msgstr "Recibiendo..."
43
44 #: src/elektroid.c:763
45 msgid "Receive SysEx"
46 msgstr "Recibir SysEx"
47
48 #: src/elektroid.c:795
49 msgid "Save SysEx"
50 msgstr "Guardar SysEx"
51
52 #: src/elektroid.c:798 src/elektroid.c:928 src/elektroid.c:1160
53 #: res/gui.glade:1617 res/gui.glade:1717
54 msgid "_Cancel"
55 msgstr "_Cancelar"
56
57 #: src/elektroid.c:800 res/gui.glade:1631
58 msgid "_Save"
59 msgstr "_Guardar"
60
61 #: src/elektroid.c:804
62 msgid "Received SysEx"
63 msgstr "SysEx recibido"
64
65 #: src/elektroid.c:809 src/elektroid.c:934
66 msgid "SysEx Files"
67 msgstr "Archivos SysEx"
68
69 #: src/elektroid.c:843
70 #, c-format
71 msgid "Error while saving “%s”: %s."
72 msgstr "Error al guardar «%s»: %s."
73
74 #: src/elektroid.c:864
75 #, c-format
76 msgid "Error while loading “%s”: %s."
77 msgstr "Error al cargar «%s»: %s."
78
79 #: src/elektroid.c:925
80 msgid "Open SysEx"
81 msgstr "Abrir SysEx"
82
83 #: src/elektroid.c:930
84 msgid "_Open"
85 msgstr "_Abrir"
86
87 #: src/elektroid.c:946
88 msgid "Sending SysEx"
89 msgstr "Enviando SysEx"
90
91 #: src/elektroid.c:1021
92 msgid "minutes"
93 msgstr "minutos"
94
95 #: src/elektroid.c:1159
96 msgid "Are you sure you want to delete the selected items?"
97 msgstr "¿Está seguro de que quiere eliminar los elementos seleccionados?"
98
99 #: src/elektroid.c:1161
100 msgid "_Delete"
101 msgstr "_Eliminar"
102
103 #: src/elektroid.c:1178
104 msgid "Deleting Files"
105 msgstr "Eliminando archivos"
106
107 #: src/elektroid.c:1179
108 msgid "Deleting..."
109 msgstr "Eliminando..."
110
111 #: src/elektroid.c:1212 res/gui.glade:121 res/gui.glade:210
112 msgid "Rename"
113 msgstr "Renombrar"
114
115 #: src/elektroid.c:1228
116 #, c-format
117 msgid "Error while renaming to “%s”: %s."
118 msgstr "Error al renombrar a «%s»: %s."
119
120 #: src/elektroid.c:1907 res/gui.glade:572 res/gui.glade:788
121 msgid "Add Directory"
122 msgstr "Añadir directorio"
123
124 #: src/elektroid.c:1925
125 #, c-format
126 msgid "Error while creating dir “%s”: %s."
127 msgstr "Error al crear el directorio «%s»: %s."
128
129 #: src/elektroid.c:1997
130 msgid "Queued"
131 msgstr "Encolada"
132
133 #: src/elektroid.c:1999
134 msgid "Running"
135 msgstr "Ejecutando"
136
137 #: src/elektroid.c:2001
138 msgid "Completed"
139 msgstr "Completada"
140
141 #: src/elektroid.c:2003
142 msgid "Completed with errors"
143 msgstr "Completada con errores"
144
145 #: src/elektroid.c:2005
146 msgid "Canceled"
147 msgstr "Cancelada"
148
149 #: src/elektroid.c:2007 src/elektroid.c:2021
36150 msgid "Undefined"
37151 msgstr "Indefinido"
38152
39 #: src/elektroid.c:434
40 #, c-format
41 msgid "Connected to %s%s"
42 msgstr "Conectado a %s%s"
43
44 #: src/elektroid.c:442 src/elektroid.c:3256
45 msgid "Not connected"
46 msgstr "No conectado"
47
48 #: src/elektroid.c:585
49 msgid "Waiting..."
50 msgstr "Esperando..."
51
52 #: src/elektroid.c:588
53 msgid "Sending..."
54 msgstr "Enviando..."
55
56 #: src/elektroid.c:592
57 msgid "Receiving..."
58 msgstr "Recibiendo..."
59
60 #: src/elektroid.c:660
61 msgid "Receive SysEx"
62 msgstr "Recibir SysEx"
63
64 #: src/elektroid.c:684
65 msgid "Save SysEx"
66 msgstr "Guardar SysEx"
67
68 #: src/elektroid.c:687 src/elektroid.c:783 src/elektroid.c:951
69 #: res/gui.glade:1332 res/gui.glade:1432
70 msgid "_Cancel"
71 msgstr "_Cancelar"
72
73 #: src/elektroid.c:689 res/gui.glade:1346
74 msgid "_Save"
75 msgstr "_Guardar"
76
77 #: src/elektroid.c:693
78 msgid "Received SysEx"
79 msgstr "SysEx recibido"
80
81 #: src/elektroid.c:698 src/elektroid.c:789
82 msgid "SysEx Files"
83 msgstr "Archivos SysEx"
84
85 #: src/elektroid.c:732
86 #, c-format
87 msgid "Error while saving “%s”: %s."
88 msgstr "Error al guardar «%s»: %s."
89
90 #: src/elektroid.c:780
91 msgid "Open SysEx"
92 msgstr "Abrir SysEx"
93
94 #: src/elektroid.c:785
95 msgid "_Open"
96 msgstr "_Abrir"
97
98 #: src/elektroid.c:806
99 #, c-format
100 msgid "Error while loading “%s”: %s."
101 msgstr "Error al cargar «%s»: %s."
102
103 #: src/elektroid.c:816
104 msgid "Send SysEx"
105 msgstr "Enviar SysEx"
106
107 #: src/elektroid.c:918
108 #, c-format
109 msgid "Error while deleting “%s”: %s."
110 msgstr "Error al eliminar «%s»: %s."
111
112 #: src/elektroid.c:950
113 msgid "Are you sure you want to delete the selected items?"
114 msgstr "¿Está seguro de que quiere eliminar los elementos seleccionados?"
115
116 #: src/elektroid.c:952
117 msgid "_Delete"
118 msgstr "_Eliminar"
119
120 #: src/elektroid.c:1005 res/gui.glade:121 res/gui.glade:174
121 msgid "Rename"
122 msgstr "Renombrar"
123
124 #: src/elektroid.c:1023
125 #, c-format
126 msgid "Error while renaming to “%s”: %s."
127 msgstr "Error al renombrar a «%s»: %s."
128
129 #: src/elektroid.c:1589 res/gui.glade:436 res/gui.glade:606
130 msgid "Add Directory"
131 msgstr "Añadir directorio"
132
133 #: src/elektroid.c:1607
134 #, c-format
135 msgid "Error while creating dir “%s”: %s."
136 msgstr "Error al crear el directorio «%s»: %s."
137
138 #: src/elektroid.c:1679
139 msgid "Queued"
140 msgstr "Encolada"
141
142 #: src/elektroid.c:1681
143 msgid "Running"
144 msgstr "Ejecutando"
145
146 #: src/elektroid.c:1683
147 msgid "Completed"
148 msgstr "Completada"
149
150 #: src/elektroid.c:1685
151 msgid "Completed with errors"
152 msgstr "Completada con errores"
153
154 #: src/elektroid.c:1687
155 msgid "Canceled"
156 msgstr "Cancelada"
157
158 #: src/elektroid.c:1699
153 #: src/elektroid.c:2017
159154 msgid "Upload"
160155 msgstr "Carga"
161156
162 #: src/elektroid.c:1701
157 #: src/elektroid.c:2019
163158 msgid "Download"
164159 msgstr "Descarga"
165160
166 #: src/elektroid.c:2560 src/elektroid.c:2601
167 #, c-format
168 msgid "Error while moving from “%s” to “%s”: %s."
169 msgstr "Error al mover de «%s» a «%s»: %s."
161 #: src/elektroid.c:2496 src/elektroid.c:2705 src/elektroid.c:3361
162 msgid "Preparing Tasks"
163 msgstr "Preparando tareas"
164
165 #: src/elektroid.c:3077
166 msgid "Connecting to Device"
167 msgstr "Conectando con el dispositivo"
168
169 #: src/elektroid.c:3078
170 msgid "Connecting..."
171 msgstr "Conectando..."
172
173 #: src/elektroid.c:3088
174 #, c-format
175 msgid "Device “%s” not recognized: %s"
176 msgstr "Dispositivo «%s» no reconocido: %s"
177
178 #: src/elektroid.c:3355
179 msgid "Moving Files"
180 msgstr "Moviendo archivos"
181
182 #: src/elektroid.c:3356
183 msgid "Moving..."
184 msgstr "Moviendo..."
185
186 #: src/local.c:492
187 msgid "System"
188 msgstr "Sistema"
189
190 #: src/connectors/sds.c:1127 src/connectors/sds.c:1133
191 msgid "SDS sampler"
192 msgstr "Sampler SDS"
170193
171194 #: res/gui.glade:70
172195 msgid "Upload Selection"
173196 msgstr "Cargar selección"
174197
175 #: res/gui.glade:85
198 #: res/gui.glade:85 res/gui.glade:174
176199 msgid "Play"
177200 msgstr "Reproducir"
178201
179 #: res/gui.glade:99
202 #: res/gui.glade:99 res/gui.glade:188
180203 msgid "Open With External Editor"
181204 msgstr "Abrir con editor externo"
182205
183 #: res/gui.glade:107
206 #: res/gui.glade:107 res/gui.glade:196
184207 msgid "Show in File Manager"
185208 msgstr "Mostrar en gestor de archivos"
186209
187 #: res/gui.glade:130 res/gui.glade:183
210 #: res/gui.glade:130 res/gui.glade:219
188211 msgid "Delete"
189212 msgstr "Eliminar"
190213
192215 msgid "Download Selection"
193216 msgstr "Descargar selección"
194217
195 #: res/gui.glade:219
218 #: res/gui.glade:255
196219 msgid "GNU/Linux transfer application for Elektron devices"
197220 msgstr "Aplicación GNU/Linux de transferencia para dispositivos Elektron"
198221
199 #: res/gui.glade:222
222 #: res/gui.glade:258
200223 msgid "translator-credits"
201224 msgstr "David García Goñi <dagargo@gmail.com>"
202225
203 #: res/gui.glade:270
226 #: res/gui.glade:306
204227 msgid "_Receive SysEx"
205228 msgstr "_Recibir SysEx"
206229
207 #: res/gui.glade:283
230 #: res/gui.glade:319
208231 msgid "_Send SysEx"
209232 msgstr "_Enviar SysEx"
210233
211 #: res/gui.glade:307
234 #: res/gui.glade:343
212235 msgid "OS _Upgrade"
213236 msgstr "Actualizar _SO"
214237
215 #: res/gui.glade:331
238 #: res/gui.glade:367
216239 msgid "_About"
217240 msgstr "_Acerca de"
218241
219 #: res/gui.glade:415 res/gui.glade:585
242 #: res/gui.glade:447
243 msgid "Refresh Devices"
244 msgstr "Actualizar dispositivos"
245
246 #: res/gui.glade:551 res/gui.glade:767
220247 msgid "Go to Parent Directory"
221248 msgstr "Ir al directorio padre"
222249
223 #: res/gui.glade:457 res/gui.glade:627
250 #: res/gui.glade:593 res/gui.glade:809
224251 msgid "Refresh Directory"
225252 msgstr "Actualizar directorio"
226253
227 #: res/gui.glade:514 res/gui.glade:694 res/gui.glade:1377
254 #: res/gui.glade:664 res/gui.glade:870 res/gui.glade:1662
228255 msgid "Name"
229256 msgstr "Nombre"
230257
231 #: res/gui.glade:528 res/gui.glade:708
258 #: res/gui.glade:678 res/gui.glade:884
232259 msgid "Size"
233260 msgstr "Tamaño"
234261
235 #: res/gui.glade:761
236 msgid "Refresh Devices"
237 msgstr "Actualizar dispositivos"
238
239262 #. It is recommended to split the text in two lines if it is too long
240 #: res/gui.glade:879
263 #: res/gui.glade:987
241264 msgid "Auto play"
242265 msgstr ""
243 "Reproducción\n"
244 "automática"
245
246 #: res/gui.glade:1101
266 "Reproducir\n"
267 "automáticamente"
268
269 #: res/gui.glade:1027
270 msgid "Playing mix depends on the destination channels"
271 msgstr "La mezcla para reproducción depende de los canales de destino"
272
273 #. It is recommended to split the text in two lines if it is too long
274 #: res/gui.glade:1029
275 msgid ""
276 "Mix depending\n"
277 "on destination"
278 msgstr ""
279 "Mezclar según\n"
280 "destino"
281
282 #: res/gui.glade:1219
283 msgid "Samples"
284 msgstr "Muestras"
285
286 #: res/gui.glade:1233
287 msgid "Channels"
288 msgstr "Canales"
289
290 #: res/gui.glade:1247
291 msgid "Sample rate"
292 msgstr "Frecuencia"
293
294 #: res/gui.glade:1261
295 msgid "Bit depth"
296 msgstr "Bits"
297
298 #: res/gui.glade:1319
299 msgid "Duration"
300 msgstr "Duración"
301
302 #: res/gui.glade:1385
247303 msgid "Status"
248304 msgstr "Estado"
249305
250 #: res/gui.glade:1112
306 #: res/gui.glade:1396
251307 msgid "Type"
252308 msgstr "Tipo"
253309
254 #: res/gui.glade:1133
310 #: res/gui.glade:1417
255311 msgid "Source"
256312 msgstr "Origen"
257313
258 #: res/gui.glade:1147
314 #: res/gui.glade:1431
259315 msgid "Destination"
260316 msgstr "Destino"
261317
262 #: res/gui.glade:1162
318 #: res/gui.glade:1446
263319 msgid "Progress"
264320 msgstr "Progreso"
265321
266 #: res/gui.glade:1194
322 #: res/gui.glade:1478
267323 msgid "Cancel Tasks"
268324 msgstr "Cancelar tareas"
269325
270 #: res/gui.glade:1215
326 #: res/gui.glade:1499
271327 msgid "Remove Queued Tasks"
272328 msgstr "Eliminar tareas encoladas"
273329
274 #: res/gui.glade:1236
330 #: res/gui.glade:1520
275331 msgid "Clear Finished Tasks"
276332 msgstr "Limpiar tareas terminadas"
+232
-176
po/fr.po less more
00 # French GUI translation for Elektroid.
1 # Copyright (C) 2019-2021 Olivier Humbert
1 # Copyright (C) 2019-2022 Olivier Humbert
22 # This file is distributed under the same license as the Elektroid package.
3 # Olivier Humbert <trebmuh@tuxfamily.org>, 2019-2021.
3 # Olivier Humbert <trebmuh@tuxfamily.org>, 2019-2022.
44 #
55 msgid ""
66 msgstr ""
7 "Project-Id-Version: elektroid 2.0\n"
7 "Project-Id-Version: elektroid 2.2\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2022-06-03 08:47+0200\n"
10 "PO-Revision-Date: 2021-12-03 17:59+0100\n"
9 "POT-Creation-Date: 2022-10-30 20:46+0100\n"
10 "PO-Revision-Date: 2022-11-01 23:05+0100\n"
1111 "Last-Translator: Olivier Humbert <trebmuh@tuxfamily.org>\n"
1212 "Language-Team: French\n"
1313 "Language: fr\n"
1616 "Content-Transfer-Encoding: 8bit\n"
1717 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
1818
19 #: src/elektroid.c:246
20 msgid "Samples"
21 msgstr "Échantillons"
22
23 #: src/elektroid.c:248
24 msgid "Presets"
25 msgstr "Préréglages"
26
27 #: src/elektroid.c:250
28 msgid "Projects"
29 msgstr "Projets"
30
31 #: src/elektroid.c:252
32 msgid "Sounds"
33 msgstr "Sons"
34
35 #: src/elektroid.c:254 src/elektroid.c:1689 src/elektroid.c:1703
19 #: src/connector.c:41 src/connector.c:47
20 msgid "MIDI device"
21 msgstr "Périphérique MIDI"
22
23 #: src/elektroid.c:526 src/elektroid.c:3952
24 msgid "Not connected"
25 msgstr "Non connecté"
26
27 #: src/elektroid.c:676
28 msgid "Cancelling..."
29 msgstr "Annulation..."
30
31 #: src/elektroid.c:697 src/elektroid.c:2497 src/elektroid.c:2706
32 #: src/elektroid.c:3362
33 msgid "Waiting..."
34 msgstr "En attente..."
35
36 #: src/elektroid.c:700
37 msgid "Sending..."
38 msgstr "Envoi en cours..."
39
40 #: src/elektroid.c:703
41 msgid "Receiving..."
42 msgstr "Réception en cours..."
43
44 #: src/elektroid.c:763
45 msgid "Receive SysEx"
46 msgstr "Réception de SysEx"
47
48 #: src/elektroid.c:795
49 msgid "Save SysEx"
50 msgstr "Sauvegarde de SysEx"
51
52 #: src/elektroid.c:798 src/elektroid.c:928 src/elektroid.c:1160
53 #: res/gui.glade:1617 res/gui.glade:1717
54 msgid "_Cancel"
55 msgstr "_Annuler"
56
57 #: src/elektroid.c:800 res/gui.glade:1631
58 msgid "_Save"
59 msgstr "_Sauvegarder"
60
61 #: src/elektroid.c:804
62 msgid "Received SysEx"
63 msgstr "SysEx reçu"
64
65 #: src/elektroid.c:809 src/elektroid.c:934
66 msgid "SysEx Files"
67 msgstr "Fichiers SysEx"
68
69 #: src/elektroid.c:843
70 #, c-format
71 msgid "Error while saving “%s”: %s."
72 msgstr "Erreur lors de la sauvegarde de « %s » : %s."
73
74 #: src/elektroid.c:864
75 #, c-format
76 msgid "Error while loading “%s”: %s."
77 msgstr "Erreur lors du chargement de « %s » : %s."
78
79 #: src/elektroid.c:925
80 msgid "Open SysEx"
81 msgstr "Ouvrir SysEx"
82
83 #: src/elektroid.c:930
84 msgid "_Open"
85 msgstr "_Ouvrir"
86
87 #: src/elektroid.c:946
88 msgid "Sending SysEx"
89 msgstr "Envoi SysEx"
90
91 #: src/elektroid.c:1021
92 msgid "minutes"
93 msgstr "minutes"
94
95 #: src/elektroid.c:1159
96 msgid "Are you sure you want to delete the selected items?"
97 msgstr "Souhaitez-vous vraiment supprimer les éléments sélectionnés ?"
98
99 #: src/elektroid.c:1161
100 msgid "_Delete"
101 msgstr "_Supprimer"
102
103 #: src/elektroid.c:1178
104 msgid "Deleting Files"
105 msgstr "Suppression des fichiers"
106
107 #: src/elektroid.c:1179
108 msgid "Deleting..."
109 msgstr "Suppression..."
110
111 #: src/elektroid.c:1212 res/gui.glade:121 res/gui.glade:210
112 msgid "Rename"
113 msgstr "Renommer"
114
115 #: src/elektroid.c:1228
116 #, c-format
117 msgid "Error while renaming to “%s”: %s."
118 msgstr "Erreur lors du renommage de « %s » : %s."
119
120 #: src/elektroid.c:1907 res/gui.glade:572 res/gui.glade:788
121 msgid "Add Directory"
122 msgstr "Ajout d'un répertoire"
123
124 #: src/elektroid.c:1925
125 #, c-format
126 msgid "Error while creating dir “%s”: %s."
127 msgstr "Erreur lors de la création du répertoire « %s » : %s."
128
129 #: src/elektroid.c:1997
130 msgid "Queued"
131 msgstr "Mise en file d'attente"
132
133 #: src/elektroid.c:1999
134 msgid "Running"
135 msgstr "En cours"
136
137 #: src/elektroid.c:2001
138 msgid "Completed"
139 msgstr "Terminé"
140
141 #: src/elektroid.c:2003
142 msgid "Completed with errors"
143 msgstr "Terminé avec des erreurs"
144
145 #: src/elektroid.c:2005
146 msgid "Canceled"
147 msgstr "Annulé"
148
149 #: src/elektroid.c:2007 src/elektroid.c:2021
36150 msgid "Undefined"
37151 msgstr "Indéfini"
38152
39 #: src/elektroid.c:434
40 #, c-format
41 msgid "Connected to %s%s"
42 msgstr "Connecté à %s%s"
43
44 #: src/elektroid.c:442 src/elektroid.c:3256
45 msgid "Not connected"
46 msgstr "Non connecté"
47
48 #: src/elektroid.c:585
49 msgid "Waiting..."
50 msgstr "En attente..."
51
52 #: src/elektroid.c:588
53 msgid "Sending..."
54 msgstr "Envoi en cours..."
55
56 #: src/elektroid.c:592
57 msgid "Receiving..."
58 msgstr "Réception en cours..."
59
60 #: src/elektroid.c:660
61 msgid "Receive SysEx"
62 msgstr "Réception de SysEx"
63
64 #: src/elektroid.c:684
65 msgid "Save SysEx"
66 msgstr "Sauvegarde de SysEx"
67
68 #: src/elektroid.c:687 src/elektroid.c:783 src/elektroid.c:951
69 #: res/gui.glade:1332 res/gui.glade:1432
70 msgid "_Cancel"
71 msgstr "_Annuler"
72
73 #: src/elektroid.c:689 res/gui.glade:1346
74 msgid "_Save"
75 msgstr "_Sauvegarder"
76
77 #: src/elektroid.c:693
78 msgid "Received SysEx"
79 msgstr "SysEx reçu"
80
81 #: src/elektroid.c:698 src/elektroid.c:789
82 msgid "SysEx Files"
83 msgstr "Fichiers SysEx"
84
85 #: src/elektroid.c:732
86 #, c-format
87 msgid "Error while saving “%s”: %s."
88 msgstr "Erreur lors de la sauvegarde de « %s » : %s."
89
90 #: src/elektroid.c:780
91 msgid "Open SysEx"
92 msgstr "Ouvrir SysEx"
93
94 #: src/elektroid.c:785
95 msgid "_Open"
96 msgstr "_Ouvrir"
97
98 #: src/elektroid.c:806
99 #, c-format
100 msgid "Error while loading “%s”: %s."
101 msgstr "Erreur lors du chargement de « %s » : %s."
102
103 #: src/elektroid.c:816
104 msgid "Send SysEx"
105 msgstr "Envoyer SysEx"
106
107 #: src/elektroid.c:918
108 #, c-format
109 msgid "Error while deleting “%s”: %s."
110 msgstr "Erreur lors de la suppression de « %s » : %s."
111
112 #: src/elektroid.c:950
113 msgid "Are you sure you want to delete the selected items?"
114 msgstr "Souhaitez-vous vraiment supprimer les éléments sélectionnés ?"
115
116 #: src/elektroid.c:952
117 msgid "_Delete"
118 msgstr "_Supprimer"
119
120 #: src/elektroid.c:1005 res/gui.glade:121 res/gui.glade:174
121 msgid "Rename"
122 msgstr "Renommer"
123
124 #: src/elektroid.c:1023
125 #, c-format
126 msgid "Error while renaming to “%s”: %s."
127 msgstr "Erreur lors du renommage de « %s » : %s."
128
129 #: src/elektroid.c:1589 res/gui.glade:436 res/gui.glade:606
130 msgid "Add Directory"
131 msgstr "Ajout d'un répertoire"
132
133 #: src/elektroid.c:1607
134 #, c-format
135 msgid "Error while creating dir “%s”: %s."
136 msgstr "Erreur lors de la création du répertoire « %s » : %s."
137
138 #: src/elektroid.c:1679
139 msgid "Queued"
140 msgstr "Mise en file d'attente"
141
142 #: src/elektroid.c:1681
143 msgid "Running"
144 msgstr "En cours"
145
146 #: src/elektroid.c:1683
147 msgid "Completed"
148 msgstr "Terminé"
149
150 #: src/elektroid.c:1685
151 msgid "Completed with errors"
152 msgstr "Terminé avec des erreurs"
153
154 #: src/elektroid.c:1687
155 msgid "Canceled"
156 msgstr "Annulé"
157
158 #: src/elektroid.c:1699
153 #: src/elektroid.c:2017
159154 msgid "Upload"
160155 msgstr "Téléversement"
161156
162 #: src/elektroid.c:1701
157 #: src/elektroid.c:2019
163158 msgid "Download"
164159 msgstr "Téléchargement"
165160
166 #: src/elektroid.c:2560 src/elektroid.c:2601
167 #, c-format
168 msgid "Error while moving from “%s” to “%s”: %s."
169 msgstr "Erreur lors du passage de « %s » à « %s » : %s."
161 #: src/elektroid.c:2496 src/elektroid.c:2705 src/elektroid.c:3361
162 msgid "Preparing Tasks"
163 msgstr "Préparation des tâches"
164
165 #: src/elektroid.c:3077
166 msgid "Connecting to Device"
167 msgstr "Connexion au périphérique"
168
169 #: src/elektroid.c:3078
170 msgid "Connecting..."
171 msgstr "Connexion..."
172
173 #: src/elektroid.c:3088
174 #, c-format
175 msgid "Device “%s” not recognized: %s"
176 msgstr "Périphérique “%s” non reconnu : %s"
177
178 #: src/elektroid.c:3355
179 msgid "Moving Files"
180 msgstr "Déplacement des fichiers"
181
182 #: src/elektroid.c:3356
183 msgid "Moving..."
184 msgstr "Déplacement..."
185
186 #: src/local.c:492
187 msgid "System"
188 msgstr "Système"
189
190 #: src/connectors/sds.c:1127 src/connectors/sds.c:1133
191 msgid "SDS sampler"
192 msgstr "échantillonneur SDS"
170193
171194 #: res/gui.glade:70
172195 msgid "Upload Selection"
173196 msgstr "Téléversement de la sélection"
174197
175 #: res/gui.glade:85
198 #: res/gui.glade:85 res/gui.glade:174
176199 msgid "Play"
177200 msgstr "Lecture"
178201
179 #: res/gui.glade:99
202 #: res/gui.glade:99 res/gui.glade:188
180203 msgid "Open With External Editor"
181204 msgstr "Ouvrir avec un éditeur externe"
182205
183 #: res/gui.glade:107
206 #: res/gui.glade:107 res/gui.glade:196
184207 msgid "Show in File Manager"
185208 msgstr "Afficher dans un ge_stionnaire de fichier"
186209
187 #: res/gui.glade:130 res/gui.glade:183
210 #: res/gui.glade:130 res/gui.glade:219
188211 msgid "Delete"
189212 msgstr "Supprimer"
190213
192215 msgid "Download Selection"
193216 msgstr "Téléchargement de la sélection"
194217
195 #: res/gui.glade:219
218 #: res/gui.glade:255
196219 msgid "GNU/Linux transfer application for Elektron devices"
197220 msgstr "Application GNU/Linux de transfert pour les périphériques Elektron"
198221
199 #: res/gui.glade:222
222 #: res/gui.glade:258
200223 msgid "translator-credits"
201224 msgstr "Olivier Humbert <trebmuh@tuxfamily.org>"
202225
203 #: res/gui.glade:270
226 #: res/gui.glade:306
204227 msgid "_Receive SysEx"
205228 msgstr "_Réception de SysEx"
206229
207 #: res/gui.glade:283
230 #: res/gui.glade:319
208231 msgid "_Send SysEx"
209232 msgstr "Envoi de _Sysex"
210233
211 #: res/gui.glade:307
234 #: res/gui.glade:343
212235 msgid "OS _Upgrade"
213236 msgstr "Mise à jo_ur SE"
214237
215 #: res/gui.glade:331
238 #: res/gui.glade:367
216239 msgid "_About"
217240 msgstr "À _propos"
218241
219 #: res/gui.glade:415 res/gui.glade:585
242 #: res/gui.glade:447
243 msgid "Refresh Devices"
244 msgstr "Rafraîchir les périphériques"
245
246 #: res/gui.glade:551 res/gui.glade:767
220247 msgid "Go to Parent Directory"
221248 msgstr "Aller au répertoire parent"
222249
223 #: res/gui.glade:457 res/gui.glade:627
250 #: res/gui.glade:593 res/gui.glade:809
224251 msgid "Refresh Directory"
225252 msgstr "Rafraîchir le répertoire"
226253
227 #: res/gui.glade:514 res/gui.glade:694 res/gui.glade:1377
254 #: res/gui.glade:664 res/gui.glade:870 res/gui.glade:1662
228255 msgid "Name"
229256 msgstr "Nom"
230257
231 #: res/gui.glade:528 res/gui.glade:708
258 #: res/gui.glade:678 res/gui.glade:884
232259 msgid "Size"
233260 msgstr "Taille"
234261
235 #: res/gui.glade:761
236 msgid "Refresh Devices"
237 msgstr "Rafraîchir les périphériques"
238
239262 #. It is recommended to split the text in two lines if it is too long
240 #: res/gui.glade:879
263 #: res/gui.glade:987
241264 msgid "Auto play"
242265 msgstr ""
243266 "Lecture\n"
244267 "automatique"
245268
246 #: res/gui.glade:1101
269 #: res/gui.glade:1027
270 msgid "Playing mix depends on the destination channels"
271 msgstr "Le mixage de lecture dépend des canaux de destination"
272
273 #. It is recommended to split the text in two lines if it is too long
274 #: res/gui.glade:1029
275 msgid ""
276 "Mix depending\n"
277 "on destination"
278 msgstr ""
279 "Mélange selon\n"
280 "la destination"
281
282 #: res/gui.glade:1219
283 msgid "Samples"
284 msgstr "Échantillons"
285
286 #: res/gui.glade:1233
287 msgid "Channels"
288 msgstr "Canaux"
289
290 #: res/gui.glade:1247
291 msgid "Sample rate"
292 msgstr "Taux d'échantillonnage"
293
294 #: res/gui.glade:1261
295 msgid "Bit depth"
296 msgstr "Débit binaire"
297
298 #: res/gui.glade:1319
299 msgid "Duration"
300 msgstr "Durée"
301
302 #: res/gui.glade:1385
247303 msgid "Status"
248 msgstr "Statut"
249
250 #: res/gui.glade:1112
304 msgstr "État"
305
306 #: res/gui.glade:1396
251307 msgid "Type"
252308 msgstr "Type"
253309
254 #: res/gui.glade:1133
310 #: res/gui.glade:1417
255311 msgid "Source"
256312 msgstr "Source"
257313
258 #: res/gui.glade:1147
314 #: res/gui.glade:1431
259315 msgid "Destination"
260316 msgstr "Destination"
261317
262 #: res/gui.glade:1162
318 #: res/gui.glade:1446
263319 msgid "Progress"
264320 msgstr "Progrès"
265321
266 #: res/gui.glade:1194
322 #: res/gui.glade:1478
267323 msgid "Cancel Tasks"
268324 msgstr "Annuler les tâches"
269325
270 #: res/gui.glade:1215
326 #: res/gui.glade:1499
271327 msgid "Remove Queued Tasks"
272328 msgstr "Supprimer les tâches dans la file d'attente"
273329
274 #: res/gui.glade:1236
330 #: res/gui.glade:1520
275331 msgid "Clear Finished Tasks"
276332 msgstr "Nettoyer les tâches terminées"
44 #
55 msgid ""
66 msgstr ""
7 "Project-Id-Version: elektroid 1.4\n"
7 "Project-Id-Version: elektroid 2.2\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2022-06-03 08:47+0200\n"
10 "PO-Revision-Date: 2021-12-01 17:56-0300\n"
9 "POT-Creation-Date: 2022-10-30 20:46+0100\n"
10 "PO-Revision-Date: 2022-11-01 18:20-0300\n"
1111 "Last-Translator: Gustavo Costa <xfgusta@gmail.com>\n"
1212 "Language-Team: \n"
1313 "Language: pt_BR\n"
1414 "MIME-Version: 1.0\n"
1515 "Content-Type: text/plain; charset=UTF-8\n"
1616 "Content-Transfer-Encoding: 8bit\n"
17 "X-Generator: Poedit 3.0\n"
1817 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
19
20 #: src/elektroid.c:246
21 msgid "Samples"
22 msgstr "Samples"
23
24 #: src/elektroid.c:248
25 msgid "Presets"
26 msgstr "Presets"
27
28 #: src/elektroid.c:250
29 msgid "Projects"
30 msgstr "Projects"
31
32 #: src/elektroid.c:252
33 msgid "Sounds"
34 msgstr "Sounds"
35
36 #: src/elektroid.c:254 src/elektroid.c:1689 src/elektroid.c:1703
18 "X-Generator: Poedit 3.1.1\n"
19
20 #: src/connector.c:41 src/connector.c:47
21 msgid "MIDI device"
22 msgstr "Dispositivo MIDI"
23
24 #: src/elektroid.c:526 src/elektroid.c:3952
25 msgid "Not connected"
26 msgstr "Não conectado"
27
28 #: src/elektroid.c:676
29 msgid "Cancelling..."
30 msgstr "Cancelando..."
31
32 #: src/elektroid.c:697 src/elektroid.c:2497 src/elektroid.c:2706
33 #: src/elektroid.c:3362
34 msgid "Waiting..."
35 msgstr "Esperando..."
36
37 #: src/elektroid.c:700
38 msgid "Sending..."
39 msgstr "Enviando..."
40
41 #: src/elektroid.c:703
42 msgid "Receiving..."
43 msgstr "Recebendo..."
44
45 #: src/elektroid.c:763
46 msgid "Receive SysEx"
47 msgstr "Receber SysEx"
48
49 #: src/elektroid.c:795
50 msgid "Save SysEx"
51 msgstr "Salvar SysEx"
52
53 #: src/elektroid.c:798 src/elektroid.c:928 src/elektroid.c:1160
54 #: res/gui.glade:1617 res/gui.glade:1717
55 msgid "_Cancel"
56 msgstr "_Cancelar"
57
58 #: src/elektroid.c:800 res/gui.glade:1631
59 msgid "_Save"
60 msgstr "_Salvar"
61
62 #: src/elektroid.c:804
63 msgid "Received SysEx"
64 msgstr "SysEx recebido"
65
66 #: src/elektroid.c:809 src/elektroid.c:934
67 msgid "SysEx Files"
68 msgstr "Arquivos SysEx"
69
70 #: src/elektroid.c:843
71 #, c-format
72 msgid "Error while saving “%s”: %s."
73 msgstr "Erro ao salvar \"%s\": %s."
74
75 #: src/elektroid.c:864
76 #, c-format
77 msgid "Error while loading “%s”: %s."
78 msgstr "Erro ao carregar \"%s\": %s."
79
80 #: src/elektroid.c:925
81 msgid "Open SysEx"
82 msgstr "Abrir SysEx"
83
84 #: src/elektroid.c:930
85 msgid "_Open"
86 msgstr "_Abrir"
87
88 #: src/elektroid.c:946
89 msgid "Sending SysEx"
90 msgstr "Enviando SysEx"
91
92 #: src/elektroid.c:1021
93 msgid "minutes"
94 msgstr "minutos"
95
96 #: src/elektroid.c:1159
97 msgid "Are you sure you want to delete the selected items?"
98 msgstr "Tem certeza de que deseja excluir os itens selecionados?"
99
100 #: src/elektroid.c:1161
101 msgid "_Delete"
102 msgstr "_Excluir"
103
104 #: src/elektroid.c:1178
105 msgid "Deleting Files"
106 msgstr "Excluindo arquivos"
107
108 #: src/elektroid.c:1179
109 msgid "Deleting..."
110 msgstr "Excluindo..."
111
112 #: src/elektroid.c:1212 res/gui.glade:121 res/gui.glade:210
113 msgid "Rename"
114 msgstr "Renomar"
115
116 #: src/elektroid.c:1228
117 #, c-format
118 msgid "Error while renaming to “%s”: %s."
119 msgstr "Erro ao renomear para \"%s\": %s."
120
121 #: src/elektroid.c:1907 res/gui.glade:572 res/gui.glade:788
122 msgid "Add Directory"
123 msgstr "Adicionar diretório"
124
125 #: src/elektroid.c:1925
126 #, c-format
127 msgid "Error while creating dir “%s”: %s."
128 msgstr "Erro ao criar diretório \"%s\": %s."
129
130 #: src/elektroid.c:1997
131 msgid "Queued"
132 msgstr "Na fila"
133
134 #: src/elektroid.c:1999
135 msgid "Running"
136 msgstr "Executando"
137
138 #: src/elektroid.c:2001
139 msgid "Completed"
140 msgstr "Completado"
141
142 #: src/elektroid.c:2003
143 msgid "Completed with errors"
144 msgstr "Completado com erros"
145
146 #: src/elektroid.c:2005
147 msgid "Canceled"
148 msgstr "Cancelado"
149
150 #: src/elektroid.c:2007 src/elektroid.c:2021
37151 msgid "Undefined"
38152 msgstr "Indefinido"
39153
40 #: src/elektroid.c:434
41 #, c-format
42 msgid "Connected to %s%s"
43 msgstr "Conectado a %s%s"
44
45 #: src/elektroid.c:442 src/elektroid.c:3256
46 msgid "Not connected"
47 msgstr "Não conectado"
48
49 #: src/elektroid.c:585
50 msgid "Waiting..."
51 msgstr "Esperando..."
52
53 #: src/elektroid.c:588
54 msgid "Sending..."
55 msgstr "Enviando..."
56
57 #: src/elektroid.c:592
58 msgid "Receiving..."
59 msgstr "Recebendo..."
60
61 #: src/elektroid.c:660
62 msgid "Receive SysEx"
63 msgstr "Receber SysEx"
64
65 #: src/elektroid.c:684
66 msgid "Save SysEx"
67 msgstr "Salvar SysEx"
68
69 #: src/elektroid.c:687 src/elektroid.c:783 src/elektroid.c:951
70 #: res/gui.glade:1332 res/gui.glade:1432
71 msgid "_Cancel"
72 msgstr "_Cancelar"
73
74 #: src/elektroid.c:689 res/gui.glade:1346
75 msgid "_Save"
76 msgstr "_Salvar"
77
78 #: src/elektroid.c:693
79 msgid "Received SysEx"
80 msgstr "SysEx recebido"
81
82 #: src/elektroid.c:698 src/elektroid.c:789
83 msgid "SysEx Files"
84 msgstr "Arquivos SysEx"
85
86 #: src/elektroid.c:732
87 #, c-format
88 msgid "Error while saving “%s”: %s."
89 msgstr "Erro ao excluir \"%s\": %s."
90
91 #: src/elektroid.c:780
92 msgid "Open SysEx"
93 msgstr "Abrir SysEx"
94
95 #: src/elektroid.c:785
96 msgid "_Open"
97 msgstr "_Abrir"
98
99 #: src/elektroid.c:806
100 #, c-format
101 msgid "Error while loading “%s”: %s."
102 msgstr "Erro ao excluir \"%s\": %s."
103
104 #: src/elektroid.c:816
105 msgid "Send SysEx"
106 msgstr "Enviar SysEx"
107
108 #: src/elektroid.c:918
109 #, c-format
110 msgid "Error while deleting “%s”: %s."
111 msgstr "Erro ao excluir \"%s\": %s."
112
113 #: src/elektroid.c:950
114 msgid "Are you sure you want to delete the selected items?"
115 msgstr "Tem certeza de que deseja excluir os itens selecionados?"
116
117 #: src/elektroid.c:952
118 msgid "_Delete"
119 msgstr "_Excluir"
120
121 #: src/elektroid.c:1005 res/gui.glade:121 res/gui.glade:174
122 msgid "Rename"
123 msgstr "Renomar"
124
125 #: src/elektroid.c:1023
126 #, c-format
127 msgid "Error while renaming to “%s”: %s."
128 msgstr "Erro ao renomear para \"%s\": %s."
129
130 #: src/elektroid.c:1589 res/gui.glade:436 res/gui.glade:606
131 msgid "Add Directory"
132 msgstr "Adicionar diretório"
133
134 #: src/elektroid.c:1607
135 #, c-format
136 msgid "Error while creating dir “%s”: %s."
137 msgstr "Erro ao criar diretório \"%s\": %s."
138
139 #: src/elektroid.c:1679
140 msgid "Queued"
141 msgstr "Na fila"
142
143 #: src/elektroid.c:1681
144 msgid "Running"
145 msgstr "Executando"
146
147 #: src/elektroid.c:1683
148 msgid "Completed"
149 msgstr "Completado"
150
151 #: src/elektroid.c:1685
152 msgid "Completed with errors"
153 msgstr "Completado com erros"
154
155 #: src/elektroid.c:1687
156 msgid "Canceled"
157 msgstr "Cancelado"
158
159 #: src/elektroid.c:1699
154 #: src/elektroid.c:2017
160155 msgid "Upload"
161156 msgstr "Upload"
162157
163 #: src/elektroid.c:1701
158 #: src/elektroid.c:2019
164159 msgid "Download"
165160 msgstr "Download"
166161
167 #: src/elektroid.c:2560 src/elektroid.c:2601
168 #, c-format
169 msgid "Error while moving from “%s” to “%s”: %s."
170 msgstr "Erro ao mover \"%s\" para \"%s\": %s."
162 #: src/elektroid.c:2496 src/elektroid.c:2705 src/elektroid.c:3361
163 msgid "Preparing Tasks"
164 msgstr "Preparando tarefas"
165
166 #: src/elektroid.c:3077
167 msgid "Connecting to Device"
168 msgstr "Conectando ao dispositivo"
169
170 #: src/elektroid.c:3078
171 msgid "Connecting..."
172 msgstr "Conectando..."
173
174 #: src/elektroid.c:3088
175 #, c-format
176 msgid "Device “%s” not recognized: %s"
177 msgstr "Dispositivo \"%s\" não reconhecido: %s"
178
179 #: src/elektroid.c:3355
180 msgid "Moving Files"
181 msgstr "Movendo arquivos"
182
183 #: src/elektroid.c:3356
184 msgid "Moving..."
185 msgstr "Movendo..."
186
187 #: src/local.c:492
188 msgid "System"
189 msgstr "Sistema"
190
191 #: src/connectors/sds.c:1127 src/connectors/sds.c:1133
192 msgid "SDS sampler"
193 msgstr "Sampler SDS"
171194
172195 #: res/gui.glade:70
173196 msgid "Upload Selection"
174197 msgstr "Seleção de upload"
175198
176 #: res/gui.glade:85
199 #: res/gui.glade:85 res/gui.glade:174
177200 msgid "Play"
178201 msgstr "Reproduzir"
179202
180 #: res/gui.glade:99
203 #: res/gui.glade:99 res/gui.glade:188
181204 msgid "Open With External Editor"
182205 msgstr "Abrir com um editor externo"
183206
184 #: res/gui.glade:107
207 #: res/gui.glade:107 res/gui.glade:196
185208 msgid "Show in File Manager"
186209 msgstr "Mostrar no gerenciador de arquivos"
187210
188 #: res/gui.glade:130 res/gui.glade:183
211 #: res/gui.glade:130 res/gui.glade:219
189212 msgid "Delete"
190213 msgstr "Excluir"
191214
193216 msgid "Download Selection"
194217 msgstr "Seleção de download"
195218
196 #: res/gui.glade:219
219 #: res/gui.glade:255
197220 msgid "GNU/Linux transfer application for Elektron devices"
198221 msgstr "Aplicativo GNU/Linux de transferência para dispositivos Elektron"
199222
200 #: res/gui.glade:222
223 #: res/gui.glade:258
201224 msgid "translator-credits"
202225 msgstr "Gustavo Costa <xfgusta@gmail.com>"
203226
204 #: res/gui.glade:270
227 #: res/gui.glade:306
205228 msgid "_Receive SysEx"
206229 msgstr "_Receber SysEx"
207230
208 #: res/gui.glade:283
231 #: res/gui.glade:319
209232 msgid "_Send SysEx"
210233 msgstr "_Enviar SysEx"
211234
212 #: res/gui.glade:307
235 #: res/gui.glade:343
213236 msgid "OS _Upgrade"
214237 msgstr "Atualizar _OS"
215238
216 #: res/gui.glade:331
239 #: res/gui.glade:367
217240 msgid "_About"
218241 msgstr "_Sobre"
219242
220 #: res/gui.glade:415 res/gui.glade:585
243 #: res/gui.glade:447
244 msgid "Refresh Devices"
245 msgstr "Atualizar dispositivos"
246
247 #: res/gui.glade:551 res/gui.glade:767
221248 msgid "Go to Parent Directory"
222249 msgstr "Ir para o diretório pai"
223250
224 #: res/gui.glade:457 res/gui.glade:627
251 #: res/gui.glade:593 res/gui.glade:809
225252 msgid "Refresh Directory"
226253 msgstr "Atualizar diretório"
227254
228 #: res/gui.glade:514 res/gui.glade:694 res/gui.glade:1377
255 #: res/gui.glade:664 res/gui.glade:870 res/gui.glade:1662
229256 msgid "Name"
230257 msgstr "Nome"
231258
232 #: res/gui.glade:528 res/gui.glade:708
259 #: res/gui.glade:678 res/gui.glade:884
233260 msgid "Size"
234261 msgstr "Tamanho"
235262
236 #: res/gui.glade:761
237 msgid "Refresh Devices"
238 msgstr "Atualizar dispositivos"
239
240263 #. It is recommended to split the text in two lines if it is too long
241 #: res/gui.glade:879
264 #: res/gui.glade:987
242265 msgid "Auto play"
243 msgstr "Reprodução automática"
244
245 #: res/gui.glade:1101
266 msgstr ""
267 "Reprodução\n"
268 "automática"
269
270 #: res/gui.glade:1027
271 msgid "Playing mix depends on the destination channels"
272 msgstr "A reprodução de mixagem depende dos canais de destino"
273
274 #. It is recommended to split the text in two lines if it is too long
275 #: res/gui.glade:1029
276 msgid ""
277 "Mix depending\n"
278 "on destination"
279 msgstr "Mixagem dependendo do destino"
280
281 #: res/gui.glade:1219
282 msgid "Samples"
283 msgstr "Amostras"
284
285 #: res/gui.glade:1233
286 msgid "Channels"
287 msgstr "Canais"
288
289 #: res/gui.glade:1247
290 msgid "Sample rate"
291 msgstr "Taxa de amostragem"
292
293 #: res/gui.glade:1261
294 msgid "Bit depth"
295 msgstr "Profundidade de bit"
296
297 #: res/gui.glade:1319
298 msgid "Duration"
299 msgstr "Duração"
300
301 #: res/gui.glade:1385
246302 msgid "Status"
247303 msgstr "Status"
248304
249 #: res/gui.glade:1112
305 #: res/gui.glade:1396
250306 msgid "Type"
251307 msgstr "Tipo"
252308
253 #: res/gui.glade:1133
309 #: res/gui.glade:1417
254310 msgid "Source"
255311 msgstr "Origem"
256312
257 #: res/gui.glade:1147
313 #: res/gui.glade:1431
258314 msgid "Destination"
259315 msgstr "Destino"
260316
261 #: res/gui.glade:1162
317 #: res/gui.glade:1446
262318 msgid "Progress"
263319 msgstr "Progresso"
264320
265 #: res/gui.glade:1194
321 #: res/gui.glade:1478
266322 msgid "Cancel Tasks"
267323 msgstr "Cancelar tarefas"
268324
269 #: res/gui.glade:1215
325 #: res/gui.glade:1499
270326 msgid "Remove Queued Tasks"
271327 msgstr "Remover tarefas em fila"
272328
273 #: res/gui.glade:1236
329 #: res/gui.glade:1520
274330 msgid "Clear Finished Tasks"
275331 msgstr "Limpar tarefas concluídas"
00 if CLI_ONLY
1 res_DATA = devices.json
1 res_DATA = elektron-devices.json
22 desktop_DATA =
33 metainfo_DATA =
44 svgicon_DATA =
55 else
6 res_DATA = gui.glade gui.css devices.json
6 res_DATA = gui.glade gui.css elektron-devices.json
77 desktop_DATA = elektroid.desktop
88 metainfo_DATA = elektroid.appdata.xml
9 svgicon_DATA = elektroid.svg elektroid-symbolic.svg elektroid-wave-symbolic.svg elektroid-data-symbolic.svg elektroid-project-symbolic.svg elektroid-sound-symbolic.svg
9 svgicon_DATA = elektroid.svg elektroid-symbolic.svg elektroid-wave-symbolic.svg elektroid-sequence-symbolic.svg elektroid-project-symbolic.svg elektroid-sound-symbolic.svg
1010 endif
1111
1212 resdir = $(datadir)/elektroid
+0
-79
res/devices.json less more
0 [{
1 "id": 4,
2 "name": "Analog Four",
3 "alias": "af",
4 "filesystems": 56,
5 "storage": 0
6 }, {
7 "id": 6,
8 "name": "Analog Keys",
9 "alias": "ak",
10 "filesystems": 56,
11 "storage": 0
12 }, {
13 "id": 8,
14 "name": "Analog Rytm",
15 "alias": "ar",
16 "filesystems": 57,
17 "storage": 3
18 }, {
19 "id": 10,
20 "name": "Analog Heat",
21 "alias": "ah",
22 "filesystems": 40,
23 "storage": 0
24 }, {
25 "id": 12,
26 "name": "Digitakt",
27 "alias": "dt",
28 "filesystems": 57,
29 "storage": 3
30 }, {
31 "id": 14,
32 "name": "Analog Four MKII",
33 "alias": "af",
34 "filesystems": 56,
35 "storage": 0
36 }, {
37 "id": 16,
38 "name": "Analog Rytm MKII",
39 "alias": "ar",
40 "filesystems": 57,
41 "storage": 3
42 }, {
43 "id": 20,
44 "name": "Digitone",
45 "alias": "dn",
46 "filesystems": 56,
47 "storage": 0
48 }, {
49 "id": 22,
50 "name": "Analog Heat MKII",
51 "alias": "ah",
52 "filesystems": 40,
53 "storage": 0
54 }, {
55 "id": 28,
56 "name": "Digitone Keys",
57 "alias": "dn",
58 "filesystems": 56,
59 "storage": 0
60 }, {
61 "id": 25,
62 "name": "Model:Samples",
63 "alias": "ms",
64 "filesystems": 57,
65 "storage": 3
66 }, {
67 "id": 27,
68 "name": "Model:Cycles",
69 "alias": "mc",
70 "filesystems": 30,
71 "storage": 1
72 }, {
73 "id": 30,
74 "name": "Syntakt",
75 "alias": "st",
76 "filesystems": 56,
77 "storage": 0
78 }]
+0
-198
res/elektroid-data-symbolic.svg less more
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!-- Created with Inkscape (http://www.inkscape.org/) -->
2
3 <svg
4 xmlns:dc="http://purl.org/dc/elements/1.1/"
5 xmlns:cc="http://creativecommons.org/ns#"
6 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
7 xmlns:svg="http://www.w3.org/2000/svg"
8 xmlns="http://www.w3.org/2000/svg"
9 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
10 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
11 width="16"
12 height="16"
13 viewBox="0 0 4.233333 4.2333333"
14 version="1.1"
15 id="svg924"
16 sodipodi:docname="elektroid-pattern-symbolic.svg"
17 inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
18 <title
19 id="title2309">elektroid pattern symbolic</title>
20 <defs
21 id="defs918" />
22 <sodipodi:namedview
23 id="base"
24 pagecolor="#ffffff"
25 bordercolor="#666666"
26 borderopacity="1.0"
27 inkscape:pageopacity="0.0"
28 inkscape:pageshadow="2"
29 inkscape:zoom="32"
30 inkscape:cx="1.6142353"
31 inkscape:cy="7.0667158"
32 inkscape:document-units="px"
33 inkscape:current-layer="layer1"
34 showgrid="true"
35 inkscape:window-width="1680"
36 inkscape:window-height="1023"
37 inkscape:window-x="0"
38 inkscape:window-y="0"
39 inkscape:window-maximized="1"
40 inkscape:pagecheckerboard="false">
41 <inkscape:grid
42 type="xygrid"
43 id="grid1511" />
44 </sodipodi:namedview>
45 <metadata
46 id="metadata921">
47 <rdf:RDF>
48 <cc:Work
49 rdf:about="">
50 <dc:format>image/svg+xml</dc:format>
51 <dc:type
52 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
53 <dc:title>elektroid pattern symbolic</dc:title>
54 <cc:license
55 rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
56 <dc:creator>
57 <cc:Agent>
58 <dc:title>David García Goñi</dc:title>
59 </cc:Agent>
60 </dc:creator>
61 </cc:Work>
62 <cc:License
63 rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
64 <cc:permits
65 rdf:resource="http://creativecommons.org/ns#Reproduction" />
66 <cc:permits
67 rdf:resource="http://creativecommons.org/ns#Distribution" />
68 <cc:requires
69 rdf:resource="http://creativecommons.org/ns#Notice" />
70 <cc:requires
71 rdf:resource="http://creativecommons.org/ns#Attribution" />
72 <cc:permits
73 rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
74 <cc:requires
75 rdf:resource="http://creativecommons.org/ns#ShareAlike" />
76 </cc:License>
77 </rdf:RDF>
78 </metadata>
79 <g
80 inkscape:label="Capa 1"
81 inkscape:groupmode="layer"
82 id="layer1"
83 transform="translate(0,-292.76667)">
84 <rect
85 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
86 id="rect1509"
87 width="0.52916372"
88 height="0.52917469"
89 x="0.26458624"
90 y="293.03125" />
91 <rect
92 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
93 id="rect1509-6-5"
94 width="0.52916372"
95 height="0.52917469"
96 x="2.3812413"
97 y="294.0896" />
98 <rect
99 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
100 id="rect1509-6"
101 width="0.52916372"
102 height="0.52917469"
103 x="2.3812411"
104 y="293.03125" />
105 <rect
106 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
107 id="rect1509-61"
108 width="0.52916372"
109 height="0.52917469"
110 x="0.26458624"
111 y="294.0896" />
112 <rect
113 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
114 id="rect1509-6-5-2"
115 width="0.52916372"
116 height="0.52917469"
117 x="2.3812416"
118 y="296.20624" />
119 <rect
120 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
121 id="rect1509-61-9"
122 width="0.52916372"
123 height="0.52917469"
124 x="0.26458624"
125 y="296.20624" />
126 <rect
127 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
128 id="rect1509-3-2-7-2"
129 width="0.52916372"
130 height="0.52917469"
131 x="3.4395683"
132 y="296.20621" />
133 <rect
134 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
135 id="rect1509-3-2-7-2-3"
136 width="0.52916372"
137 height="0.52917469"
138 x="0.26458624"
139 y="295.14792" />
140 <rect
141 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
142 id="rect1509-3-2-7-2-6"
143 width="0.52916372"
144 height="0.52917469"
145 x="3.4395683"
146 y="293.03125" />
147 <rect
148 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
149 id="rect1509-3-2-7-2-7"
150 width="0.52916372"
151 height="0.52917469"
152 x="1.3229138"
153 y="293.03125" />
154 <rect
155 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
156 id="rect1509-3-2-7-2-5"
157 width="0.52916372"
158 height="0.52917469"
159 x="1.3229138"
160 y="295.14792" />
161 <rect
162 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
163 id="rect1509-61-7"
164 width="0.52916372"
165 height="0.52917469"
166 x="3.4395683"
167 y="295.14792" />
168 <rect
169 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
170 id="rect1509-3-2-7-2-7-6"
171 width="0.52916372"
172 height="0.52917469"
173 x="1.3229135"
174 y="294.08957" />
175 <rect
176 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
177 id="rect1509-3-2-7-2-7-2"
178 width="0.52916372"
179 height="0.52917469"
180 x="3.4395683"
181 y="294.08957" />
182 <rect
183 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
184 id="rect1509-3-2-7-2-7-9"
185 width="0.52916372"
186 height="0.52917469"
187 x="1.3229138"
188 y="296.20621" />
189 <rect
190 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
191 id="rect1509-3-2-7-2-7-1"
192 width="0.52916372"
193 height="0.52917469"
194 x="2.3812411"
195 y="295.14792" />
196 </g>
197 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!-- Created with Inkscape (http://www.inkscape.org/) -->
2
3 <svg
4 xmlns:dc="http://purl.org/dc/elements/1.1/"
5 xmlns:cc="http://creativecommons.org/ns#"
6 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
7 xmlns:svg="http://www.w3.org/2000/svg"
8 xmlns="http://www.w3.org/2000/svg"
9 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
10 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
11 width="16"
12 height="16"
13 viewBox="0 0 4.233333 4.2333333"
14 version="1.1"
15 id="svg924"
16 sodipodi:docname="elektroid-sequence-symbolic.svg"
17 inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
18 <title
19 id="title2309">elektroid sequence symbolic</title>
20 <defs
21 id="defs918" />
22 <sodipodi:namedview
23 id="base"
24 pagecolor="#ffffff"
25 bordercolor="#666666"
26 borderopacity="1.0"
27 inkscape:pageopacity="0.0"
28 inkscape:pageshadow="2"
29 inkscape:zoom="32"
30 inkscape:cx="1.6142353"
31 inkscape:cy="7.0667158"
32 inkscape:document-units="px"
33 inkscape:current-layer="layer1"
34 showgrid="true"
35 inkscape:window-width="1680"
36 inkscape:window-height="1023"
37 inkscape:window-x="0"
38 inkscape:window-y="0"
39 inkscape:window-maximized="1"
40 inkscape:pagecheckerboard="false">
41 <inkscape:grid
42 type="xygrid"
43 id="grid1511" />
44 </sodipodi:namedview>
45 <metadata
46 id="metadata921">
47 <rdf:RDF>
48 <cc:Work
49 rdf:about="">
50 <dc:format>image/svg+xml</dc:format>
51 <dc:type
52 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
53 <dc:title>elektroid sequence symbolic</dc:title>
54 <cc:license
55 rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
56 <dc:creator>
57 <cc:Agent>
58 <dc:title>David García Goñi</dc:title>
59 </cc:Agent>
60 </dc:creator>
61 </cc:Work>
62 <cc:License
63 rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
64 <cc:permits
65 rdf:resource="http://creativecommons.org/ns#Reproduction" />
66 <cc:permits
67 rdf:resource="http://creativecommons.org/ns#Distribution" />
68 <cc:requires
69 rdf:resource="http://creativecommons.org/ns#Notice" />
70 <cc:requires
71 rdf:resource="http://creativecommons.org/ns#Attribution" />
72 <cc:permits
73 rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
74 <cc:requires
75 rdf:resource="http://creativecommons.org/ns#ShareAlike" />
76 </cc:License>
77 </rdf:RDF>
78 </metadata>
79 <g
80 inkscape:label="Capa 1"
81 inkscape:groupmode="layer"
82 id="layer1"
83 transform="translate(0,-292.76667)">
84 <rect
85 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
86 id="rect1509"
87 width="0.52916372"
88 height="0.52917469"
89 x="0.26458624"
90 y="293.03125" />
91 <rect
92 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
93 id="rect1509-6-5"
94 width="0.52916372"
95 height="0.52917469"
96 x="2.3812413"
97 y="294.0896" />
98 <rect
99 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
100 id="rect1509-6"
101 width="0.52916372"
102 height="0.52917469"
103 x="2.3812411"
104 y="293.03125" />
105 <rect
106 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
107 id="rect1509-61"
108 width="0.52916372"
109 height="0.52917469"
110 x="0.26458624"
111 y="294.0896" />
112 <rect
113 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
114 id="rect1509-6-5-2"
115 width="0.52916372"
116 height="0.52917469"
117 x="2.3812416"
118 y="296.20624" />
119 <rect
120 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
121 id="rect1509-61-9"
122 width="0.52916372"
123 height="0.52917469"
124 x="0.26458624"
125 y="296.20624" />
126 <rect
127 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
128 id="rect1509-3-2-7-2"
129 width="0.52916372"
130 height="0.52917469"
131 x="3.4395683"
132 y="296.20621" />
133 <rect
134 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
135 id="rect1509-3-2-7-2-3"
136 width="0.52916372"
137 height="0.52917469"
138 x="0.26458624"
139 y="295.14792" />
140 <rect
141 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
142 id="rect1509-3-2-7-2-6"
143 width="0.52916372"
144 height="0.52917469"
145 x="3.4395683"
146 y="293.03125" />
147 <rect
148 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
149 id="rect1509-3-2-7-2-7"
150 width="0.52916372"
151 height="0.52917469"
152 x="1.3229138"
153 y="293.03125" />
154 <rect
155 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
156 id="rect1509-3-2-7-2-5"
157 width="0.52916372"
158 height="0.52917469"
159 x="1.3229138"
160 y="295.14792" />
161 <rect
162 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
163 id="rect1509-61-7"
164 width="0.52916372"
165 height="0.52917469"
166 x="3.4395683"
167 y="295.14792" />
168 <rect
169 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
170 id="rect1509-3-2-7-2-7-6"
171 width="0.52916372"
172 height="0.52917469"
173 x="1.3229135"
174 y="294.08957" />
175 <rect
176 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
177 id="rect1509-3-2-7-2-7-2"
178 width="0.52916372"
179 height="0.52917469"
180 x="3.4395683"
181 y="294.08957" />
182 <rect
183 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
184 id="rect1509-3-2-7-2-7-9"
185 width="0.52916372"
186 height="0.52917469"
187 x="1.3229138"
188 y="296.20621" />
189 <rect
190 style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001194;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
191 id="rect1509-3-2-7-2-7-1"
192 width="0.52916372"
193 height="0.52917469"
194 x="2.3812411"
195 y="295.14792" />
196 </g>
197 </svg>
1414 sodipodi:docname="elektroid-sound-symbolic.svg"
1515 inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
1616 <title
17 id="title2309">elektroid pattern symbolic</title>
17 id="title2309">elektroid sound symbolic</title>
1818 <defs
1919 id="defs918" />
2020 <sodipodi:namedview
2424 borderopacity="1.0"
2525 inkscape:pageopacity="0.0"
2626 inkscape:pageshadow="2"
27 inkscape:zoom="32"
28 inkscape:cx="7.0754366"
29 inkscape:cy="5.4255657"
27 inkscape:zoom="22.627418"
28 inkscape:cx="8.2300275"
29 inkscape:cy="9.7982109"
3030 inkscape:document-units="px"
3131 inkscape:current-layer="layer1"
3232 showgrid="true"
33 inkscape:window-width="1680"
34 inkscape:window-height="1013"
33 inkscape:window-width="1920"
34 inkscape:window-height="1043"
3535 inkscape:window-x="0"
3636 inkscape:window-y="0"
3737 inkscape:window-maximized="1"
4949 <dc:format>image/svg+xml</dc:format>
5050 <dc:type
5151 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
52 <dc:title>elektroid pattern symbolic</dc:title>
52 <dc:title>elektroid sound symbolic</dc:title>
5353 <cc:license
5454 rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
5555 <dc:creator>
8181 id="layer1"
8282 transform="translate(0,-292.76667)">
8383 <rect
84 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.187104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
85 id="rect1509-5-3-7-9-1"
86 width="0.26458329"
87 height="3.7041705"
88 x="-2.6577149e-07"
89 y="293.03125" />
90 <rect
91 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.111814;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
92 id="rect1509-5-3-7-2-2"
93 width="1.3229165"
94 height="0.26457092"
95 x="0.26458332"
96 y="296.73541" />
97 <rect
98 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.187103;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
99 id="rect1509-5-3-7-28-70"
84 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.150018;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
85 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-4"
86 width="0.79376954"
87 height="0.79374981"
88 x="-1.3229316"
89 y="-293.82498"
90 transform="scale(-1)" />
91 <rect
92 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0866093;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
93 id="rect1509-5-3-7-2-8-1-54-7-2-5-6-1-7"
94 width="0.79374123"
95 height="0.26456764"
96 x="0.52916944"
97 y="-293.56042"
98 transform="scale(1,-1)" />
99 <rect
100 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0866115;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
101 id="rect1509-5-3-7-28-70-1-0-6-6-6"
100102 width="0.2645832"
101 height="3.7041516"
102 x="1.5874999"
103 y="293.03125" />
104 <rect
105 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.111817;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
106 id="rect1509-5-3-7-97-9"
107 width="1.3229165"
108 height="0.26458609"
109 x="0.26458332"
110 y="292.76666" />
111 <rect
112 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.244977;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
113 id="rect1509-5-3-7-97-3-36"
114 width="0.79374999"
115 height="2.1166649"
116 x="0.52916646"
117 y="294.0896" />
118 <rect
119 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.187104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
120 id="rect1509-5-3-7-9-3"
121 width="0.26458329"
122 height="3.7041705"
123 x="2.3812494"
124 y="293.03125" />
125 <rect
126 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.111814;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
127 id="rect1509-5-3-7-2-6"
128 width="1.3229165"
129 height="0.26457092"
130 x="2.6458328"
131 y="296.73541" />
132 <rect
133 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.187103;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
134 id="rect1509-5-3-7-28-7"
103 height="0.79374993"
104 x="0.79375684"
105 y="-293.82498"
106 transform="scale(1,-1)" />
107 <rect
108 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.150018;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
109 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-6"
110 width="0.79376954"
111 height="0.79374981"
112 x="-3.7042093"
113 y="-295.14789"
114 transform="scale(-1)" />
115 <rect
116 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0866093;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
117 id="rect1509-5-3-7-2-8-1-54-7-2-5-6-1-9"
118 width="0.79374123"
119 height="0.26456764"
120 x="2.9104471"
121 y="-294.8833"
122 transform="scale(1,-1)" />
123 <rect
124 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0866115;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
125 id="rect1509-5-3-7-28-70-1-0-6-6-3"
135126 width="0.2645832"
136 height="3.7041516"
137 x="3.9687495"
138 y="293.03125" />
139 <rect
140 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.111817;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
141 id="rect1509-5-3-7-97-5"
142 width="1.3229165"
143 height="0.26458609"
144 x="2.645833"
145 y="292.76666" />
146 <rect
147 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.122488;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
148 id="rect1509-5-3-7-97-3-3"
149 width="0.79374999"
150 height="0.52916795"
151 x="2.9104161"
152 y="295.67709" />
153 <rect
154 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500042;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
155 id="rect1509-5-3-7-2-8-1-54-7"
156 width="0.26458338"
127 height="0.79374993"
128 x="3.1750345"
129 y="-295.14789"
130 transform="scale(1,-1)" />
131 <rect
132 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.15813;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
133 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-4-3-9"
134 width="2.6458304"
135 height="0.26458338"
136 x="-3.9687448"
137 y="-293.56042"
138 transform="scale(-1)" />
139 <rect
140 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.15813;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
141 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-4-3-1"
142 width="2.6458244"
143 height="0.26458338"
144 x="-2.9104166"
145 y="-294.88333"
146 transform="scale(-1)" />
147 <rect
148 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.150018;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
149 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-2"
150 width="0.79376954"
151 height="0.79374981"
152 x="-2.1166787"
153 y="-296.47083"
154 transform="scale(-1)" />
155 <rect
156 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0866093;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
157 id="rect1509-5-3-7-2-8-1-54-7-2-5-6-1-6"
158 width="0.79374123"
157159 height="0.26456764"
158 x="3.1749995"
159 y="296.20627" />
160 <rect
161 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
162 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9"
163 width="0.26458341"
164 height="0.26457989"
165 x="-3.1749992"
166 y="296.20624"
167 transform="scale(-1,1)" />
168 <rect
169 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
170 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-2"
171 width="0.26458341"
172 height="0.26457989"
173 x="-3.7041659"
174 y="296.20624"
175 transform="scale(-1,1)" />
176 <rect
177 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500042;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
178 id="rect1509-5-3-7-2-8-1-54-7-2"
179 width="0.26458338"
180 height="0.26456764"
181 x="0.79375052"
182 y="296.20627" />
183 <rect
184 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
185 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-8"
186 width="0.26458341"
187 height="0.26457989"
188 x="-0.79375005"
189 y="296.20624"
190 transform="scale(-1,1)" />
191 <rect
192 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
193 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-2-9"
194 width="0.26458341"
195 height="0.26457989"
196 x="-1.3229167"
197 y="296.20624"
198 transform="scale(-1,1)" />
199 <rect
200 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
201 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-7"
202 width="0.26458341"
203 height="0.26457989"
204 x="-4.2333326"
205 y="296.73541"
206 transform="scale(-1,1)" />
207 <rect
208 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
209 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-3"
210 width="0.26458341"
211 height="0.26457989"
212 x="-2.6458328"
213 y="296.73541"
214 transform="scale(-1,1)" />
215 <rect
216 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
217 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-6"
218 width="0.26458341"
219 height="0.26457989"
220 x="-1.852083"
221 y="296.73541"
222 transform="scale(-1,1)" />
223 <rect
224 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
225 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1"
226 width="0.26458341"
227 height="0.26457989"
228 x="-0.26458284"
229 y="296.73541"
230 transform="scale(-1,1)" />
231 <rect
232 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
233 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-2"
234 width="0.26458341"
235 height="0.26457989"
236 x="-0.26458284"
237 y="292.76666"
238 transform="scale(-1,1)" />
239 <rect
240 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
241 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-9"
242 width="0.26458341"
243 height="0.26457989"
244 x="-1.852083"
245 y="292.76666"
246 transform="scale(-1,1)" />
247 <rect
248 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
249 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-31"
250 width="0.26458341"
251 height="0.26457989"
252 x="-2.6458328"
253 y="292.76666"
254 transform="scale(-1,1)" />
255 <rect
256 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
257 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-94"
258 width="0.26458341"
259 height="0.26457989"
260 x="-4.2333326"
261 y="292.76666"
262 transform="scale(-1,1)" />
263 <rect
264 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500042;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
265 id="rect1509-5-3-7-2-8-1-54-7-2-3"
266 width="0.26458338"
267 height="0.26456764"
268 x="0.79374999"
269 y="293.82504" />
270 <rect
271 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
272 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-8-6"
273 width="0.26458341"
274 height="0.26457989"
275 x="-0.79374951"
276 y="293.82501"
277 transform="scale(-1,1)" />
278 <rect
279 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
280 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-2-9-7"
281 width="0.26458341"
282 height="0.26457989"
283 x="-1.3229162"
284 y="293.82501"
285 transform="scale(-1,1)" />
286 <rect
287 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500042;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
288 id="rect1509-5-3-7-2-8-1-54-7-2-5"
289 width="0.26458338"
290 height="0.26456764"
291 x="3.1750004"
292 y="295.41254" />
293 <rect
294 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
295 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-8-3"
296 width="0.26458341"
297 height="0.26457989"
298 x="-3.175"
299 y="295.41251"
300 transform="scale(-1,1)" />
301 <rect
302 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
303 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-2-9-5"
304 width="0.26458341"
305 height="0.26457989"
306 x="-3.7041667"
307 y="295.41251"
308 transform="scale(-1,1)" />
309 <rect
310 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
311 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1-6"
312 width="0.26458341"
313 height="0.26457989"
314 x="-0.52916616"
315 y="296.47083"
316 transform="scale(-1,1)" />
317 <rect
318 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
319 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1-2"
320 width="0.26458341"
321 height="0.26457989"
322 x="-1.5874995"
323 y="296.47083"
324 transform="scale(-1,1)" />
325 <rect
326 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
327 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1-9"
328 width="0.26458341"
329 height="0.26457989"
330 x="-1.5874995"
331 y="293.03125"
332 transform="scale(-1,1)" />
333 <rect
334 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
335 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1-1"
336 width="0.26458341"
337 height="0.26457989"
338 x="-0.52916616"
339 y="293.03125"
340 transform="scale(-1,1)" />
341 <rect
342 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
343 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1-27"
344 width="0.26458341"
345 height="0.26457989"
346 x="-2.9104161"
347 y="293.03125"
348 transform="scale(-1,1)" />
349 <rect
350 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
351 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1-0"
352 width="0.26458341"
353 height="0.26457989"
354 x="-3.9687493"
355 y="293.03125"
356 transform="scale(-1,1)" />
357 <rect
358 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
359 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1-93"
360 width="0.26458341"
361 height="0.26457989"
362 x="-3.9687493"
363 y="296.47083"
364 transform="scale(-1,1)" />
365 <rect
366 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500054;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
367 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-0-1-60"
368 width="0.26458341"
369 height="0.26457989"
370 x="-2.9104161"
371 y="296.47083"
372 transform="scale(-1,1)" />
160 x="1.3229166"
161 y="-296.20624"
162 transform="scale(1,-1)" />
163 <rect
164 style="fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0866115;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
165 id="rect1509-5-3-7-28-70-1-0-6-6-1"
166 width="0.2645832"
167 height="0.79374993"
168 x="1.587504"
169 y="-296.47083"
170 transform="scale(1,-1)" />
171 <rect
172 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.1323;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
173 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-4-3-0-7"
174 width="1.8520782"
175 height="0.26458338"
176 x="-3.9687448"
177 y="-296.20627"
178 transform="scale(-1)" />
179 <rect
180 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500053;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
181 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-4-3-1-2"
182 width="0.26458585"
183 height="0.26458338"
184 x="-3.9687662"
185 y="-294.88333"
186 transform="scale(-1)" />
187 <rect
188 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.100011;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
189 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-4-3-1-2-7"
190 width="1.0583394"
191 height="0.26458338"
192 x="-1.3229166"
193 y="-296.20627"
194 transform="scale(-1)" />
195 <rect
196 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0500043;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
197 id="rect1509-3-2-7-2-7-6-2-7-5-8-64-19-2-9-9-0-6-4-3-1-28"
198 width="0.26457459"
199 height="0.26458338"
200 x="-0.52916944"
201 y="-293.56042"
202 transform="scale(-1)" />
373203 </g>
374204 </svg>
0 [{
1 "id": 4,
2 "name": "Analog Four",
3 "alias": "af",
4 "filesystems": 56,
5 "storage": 0
6 }, {
7 "id": 6,
8 "name": "Analog Keys",
9 "alias": "ak",
10 "filesystems": 56,
11 "storage": 0
12 }, {
13 "id": 8,
14 "name": "Analog Rytm",
15 "alias": "ar",
16 "filesystems": 57,
17 "storage": 3
18 }, {
19 "id": 10,
20 "name": "Analog Heat",
21 "alias": "ah",
22 "filesystems": 40,
23 "storage": 0
24 }, {
25 "id": 12,
26 "name": "Digitakt",
27 "alias": "dt",
28 "filesystems": 57,
29 "storage": 3
30 }, {
31 "id": 14,
32 "name": "Analog Four MKII",
33 "alias": "af",
34 "filesystems": 56,
35 "storage": 0
36 }, {
37 "id": 16,
38 "name": "Analog Rytm MKII",
39 "alias": "ar",
40 "filesystems": 57,
41 "storage": 3
42 }, {
43 "id": 20,
44 "name": "Digitone",
45 "alias": "dn",
46 "filesystems": 56,
47 "storage": 0
48 }, {
49 "id": 22,
50 "name": "Analog Heat MKII",
51 "alias": "ah",
52 "filesystems": 40,
53 "storage": 0
54 }, {
55 "id": 28,
56 "name": "Digitone Keys",
57 "alias": "dn",
58 "filesystems": 56,
59 "storage": 0
60 }, {
61 "id": 25,
62 "name": "Model:Samples",
63 "alias": "ms",
64 "filesystems": 57,
65 "storage": 3
66 }, {
67 "id": 27,
68 "name": "Model:Cycles",
69 "alias": "mc",
70 "filesystems": 30,
71 "storage": 1
72 }, {
73 "id": 30,
74 "name": "Syntakt",
75 "alias": "st",
76 "filesystems": 56,
77 "storage": 0
78 }]
00 @define-color local_color #3584e4;
11 @define-color local_color_dark #255c9f;
22 @define-color remote_color #e01b24;
3 @define-color remote_color_dark #9d1319;
34 @define-color disabled_color #7f7f7f;
45
56 .local {
67 color: @local_color;
78 }
89
9 #local_up_button, #local_add_dir_button, #local_refresh_button, #play_button, #stop_button, #loop_button, #upload_button {
10 .remote {
11 color: @remote_color;
12 }
13
14 .local_switch {
15 background-color: @local_color_dark;
16 }
17
18 .local_switch:checked, .local_switch:checked slider {
19 border-color: @local_color_dark;
20 background-color: @local_color;
21 }
22
23 .remote_switch {
24 background-color: @remote_color_dark;
25 }
26
27 .remote_switch:checked, .remote_switch:checked slider {
28 border-color: @remote_color_dark;
29 background-color: @remote_color;
30 }
31
32 #local_up_button, #local_add_dir_button, #local_refresh_button, #upload_button {
1033 color: @local_color;
1134 }
1235
13 #remote_up_button, #remote_add_dir_button, #remote_refresh_button, #refresh_devices_button, #download_button {
36 #remote_up_button, #remote_add_dir_button, #remote_refresh_button, #download_button, #refresh_devices_button {
1437 color: @remote_color
1538 }
1639
1841 color: @disabled_color;
1942 }
2043
21 #autoplay_switch:checked, #autoplay_switch:checked slider {
22 border-color: @local_color_dark;
23 }
24
25 #local_tree_view:selected, #autoplay_switch:checked {
44 #local_tree_view:selected {
2645 background-color: @local_color;
2746 }
2847
2727 <!-- interface-copyright David Garc\303\255a Go\303\261i -->
2828 <object class="GtkListStore" id="devices_list_store">
2929 <columns>
30 <!-- column-name card -->
31 <column type="guint"/>
30 <!-- column-name id -->
31 <column type="gchararray"/>
3232 <!-- column-name name -->
3333 <column type="gchararray"/>
3434 </columns>
5050 <!-- column-name name -->
5151 <column type="gchararray"/>
5252 <!-- column-name size -->
53 <column type="gint"/>
53 <column type="gint64"/>
5454 <!-- column-name size_str -->
5555 <column type="gchararray"/>
5656 <!-- column-name type -->
5757 <column type="gint"/>
58 <!-- column-name index -->
58 <!-- column-name id -->
5959 <column type="gint"/>
60 <!-- column-name slot -->
61 <column type="gchararray"/>
6062 </columns>
6163 </object>
6264 <object class="GtkMenu" id="local_menu">
7274 </object>
7375 </child>
7476 <child>
75 <object class="GtkSeparatorMenuItem">
77 <object class="GtkSeparatorMenuItem" id="local_play_separator">
7678 <property name="visible">True</property>
7779 <property name="can-focus">False</property>
7880 </object>
139141 <!-- column-name name -->
140142 <column type="gchararray"/>
141143 <!-- column-name size -->
142 <column type="gint"/>
144 <column type="gint64"/>
143145 <!-- column-name size_str -->
144146 <column type="gchararray"/>
145147 <!-- column-name type -->
146148 <column type="gint"/>
147 <!-- column-name index -->
149 <!-- column-name id -->
148150 <column type="gint"/>
151 <!-- column-name slot -->
152 <column type="gchararray"/>
149153 </columns>
150154 </object>
151155 <object class="GtkMenu" id="remote_menu">
161165 </object>
162166 </child>
163167 <child>
164 <object class="GtkSeparatorMenuItem">
168 <object class="GtkSeparatorMenuItem" id="remote_play_separator">
169 <property name="visible">True</property>
170 <property name="can-focus">False</property>
171 </object>
172 </child>
173 <child>
174 <object class="GtkMenuItem" id="remote_play_menuitem">
175 <property name="visible">True</property>
176 <property name="can-focus">False</property>
177 <property name="label" translatable="yes">Play</property>
178 <property name="use-underline">True</property>
179 </object>
180 </child>
181 <child>
182 <object class="GtkSeparatorMenuItem" id="remote_options_separator">
183 <property name="visible">True</property>
184 <property name="can-focus">False</property>
185 </object>
186 </child>
187 <child>
188 <object class="GtkMenuItem" id="remote_open_menuitem">
189 <property name="visible">True</property>
190 <property name="can-focus">False</property>
191 <property name="label" translatable="yes">Open With External Editor</property>
192 <property name="use-underline">True</property>
193 </object>
194 </child>
195 <child>
196 <object class="GtkMenuItem" id="remote_show_menuitem">
197 <property name="visible">True</property>
198 <property name="can-focus">False</property>
199 <property name="label" translatable="yes">Show in File Manager</property>
200 <property name="use-underline">True</property>
201 </object>
202 </child>
203 <child>
204 <object class="GtkSeparatorMenuItem" id="remote_actions_separator">
165205 <property name="visible">True</property>
166206 <property name="can-focus">False</property>
167207 </object>
382422 <object class="GtkBox">
383423 <property name="visible">True</property>
384424 <property name="can-focus">False</property>
385 <property name="hexpand">True</property>
386 <property name="vexpand">True</property>
387 <property name="orientation">vertical</property>
388425 <property name="spacing">6</property>
389426 <child>
390 <object class="GtkBox">
427 <object class="GtkComboBox" id="devices_combo">
391428 <property name="visible">True</property>
392429 <property name="can-focus">False</property>
393430 <property name="hexpand">True</property>
394 <property name="spacing">6</property>
395 <child>
396 <object class="GtkEntry" id="local_dir_entry">
397 <property name="visible">True</property>
398 <property name="can-focus">True</property>
399 <property name="hexpand">True</property>
400 <property name="editable">False</property>
401 </object>
402 <packing>
403 <property name="expand">False</property>
404 <property name="fill">True</property>
405 <property name="position">0</property>
406 </packing>
407 </child>
408 <child>
409 <object class="GtkButton" id="local_up_button">
410 <property name="name">local_up_button</property>
411 <property name="visible">True</property>
412 <property name="can-focus">True</property>
413 <property name="receives-default">True</property>
414 <property name="tooltip-text" translatable="yes">Go to Parent Directory</property>
415 <child>
416 <object class="GtkImage">
417 <property name="visible">True</property>
418 <property name="can-focus">False</property>
419 <property name="icon-name">go-up-symbolic</property>
420 </object>
421 </child>
422 </object>
423 <packing>
424 <property name="expand">False</property>
425 <property name="fill">True</property>
426 <property name="position">1</property>
427 </packing>
428 </child>
429 <child>
430 <object class="GtkButton" id="local_add_dir_button">
431 <property name="name">local_up_button</property>
432 <property name="visible">True</property>
433 <property name="can-focus">True</property>
434 <property name="receives-default">True</property>
435 <property name="tooltip-text" translatable="yes">Add Directory</property>
436 <child>
437 <object class="GtkImage">
438 <property name="visible">True</property>
439 <property name="can-focus">False</property>
440 <property name="icon-name">folder-new-symbolic</property>
441 </object>
442 </child>
443 </object>
444 <packing>
445 <property name="expand">False</property>
446 <property name="fill">True</property>
447 <property name="position">2</property>
448 </packing>
449 </child>
450 <child>
451 <object class="GtkButton" id="local_refresh_button">
452 <property name="name">local_refresh_button</property>
453 <property name="visible">True</property>
454 <property name="can-focus">True</property>
455 <property name="receives-default">True</property>
456 <property name="tooltip-text" translatable="yes">Refresh Directory</property>
457 <child>
458 <object class="GtkImage">
459 <property name="visible">True</property>
460 <property name="can-focus">False</property>
461 <property name="icon-name">view-refresh-symbolic</property>
462 </object>
463 </child>
464 </object>
465 <packing>
466 <property name="expand">False</property>
467 <property name="fill">True</property>
468 <property name="position">3</property>
469 </packing>
470 </child>
471 </object>
472 <packing>
473 <property name="expand">False</property>
474 <property name="fill">True</property>
475 <property name="position">0</property>
476 </packing>
477 </child>
478 <child>
479 <object class="GtkScrolledWindow">
480 <property name="width-request">400</property>
481 <property name="height-request">200</property>
482 <property name="visible">True</property>
483 <property name="can-focus">True</property>
484 <property name="hexpand">True</property>
485 <property name="vexpand">True</property>
486 <property name="shadow-type">in</property>
487 <child>
488 <object class="GtkTreeView" id="local_tree_view">
489 <property name="name">local_tree_view</property>
490 <property name="visible">True</property>
491 <property name="can-focus">True</property>
492 <property name="hexpand">True</property>
493 <property name="vexpand">True</property>
494 <property name="model">local_list_store</property>
495 <property name="search-column">1</property>
496 <child internal-child="selection">
497 <object class="GtkTreeSelection">
498 <property name="mode">multiple</property>
499 </object>
500 </child>
501 <child>
502 <object class="GtkTreeViewColumn">
503 <child>
504 <object class="GtkCellRendererPixbuf"/>
505 <attributes>
506 <attribute name="icon-name">0</attribute>
507 </attributes>
508 </child>
509 </object>
510 </child>
511 <child>
512 <object class="GtkTreeViewColumn">
513 <property name="title" translatable="yes">Name</property>
514 <property name="expand">True</property>
515 <child>
516 <object class="GtkCellRendererText">
517 <property name="ellipsize">middle</property>
518 </object>
519 <attributes>
520 <attribute name="text">1</attribute>
521 </attributes>
522 </child>
523 </object>
524 </child>
525 <child>
526 <object class="GtkTreeViewColumn">
527 <property name="title" translatable="yes">Size</property>
528 <child>
529 <object class="GtkCellRendererText"/>
530 <attributes>
531 <attribute name="text">3</attribute>
532 </attributes>
533 </child>
534 </object>
535 </child>
536 </object>
537 </child>
538 </object>
539 <packing>
540 <property name="expand">False</property>
541 <property name="fill">True</property>
542 <property name="position">1</property>
543 </packing>
544 </child>
545 </object>
546 <packing>
547 <property name="left-attach">0</property>
548 <property name="top-attach">1</property>
549 </packing>
550 </child>
551 <child>
552 <object class="GtkBox" id="remote_box">
553 <property name="visible">True</property>
554 <property name="can-focus">False</property>
555 <property name="hexpand">True</property>
556 <property name="vexpand">True</property>
557 <property name="orientation">vertical</property>
558 <property name="spacing">6</property>
559 <child>
560 <object class="GtkBox">
561 <property name="visible">True</property>
562 <property name="can-focus">False</property>
563 <property name="hexpand">True</property>
564 <property name="spacing">6</property>
565 <child>
566 <object class="GtkEntry" id="remote_dir_entry">
567 <property name="visible">True</property>
568 <property name="can-focus">True</property>
569 <property name="hexpand">True</property>
570 <property name="editable">False</property>
571 </object>
572 <packing>
573 <property name="expand">False</property>
574 <property name="fill">True</property>
575 <property name="position">0</property>
576 </packing>
577 </child>
578 <child>
579 <object class="GtkButton" id="remote_up_button">
580 <property name="name">remote_up_button</property>
581 <property name="visible">True</property>
582 <property name="can-focus">True</property>
583 <property name="receives-default">True</property>
584 <property name="tooltip-text" translatable="yes">Go to Parent Directory</property>
585 <child>
586 <object class="GtkImage">
587 <property name="visible">True</property>
588 <property name="can-focus">False</property>
589 <property name="icon-name">go-up-symbolic</property>
590 </object>
591 </child>
592 </object>
593 <packing>
594 <property name="expand">False</property>
595 <property name="fill">True</property>
596 <property name="position">1</property>
597 </packing>
598 </child>
599 <child>
600 <object class="GtkButton" id="remote_add_dir_button">
601 <property name="name">remote_up_button</property>
602 <property name="visible">True</property>
603 <property name="can-focus">True</property>
604 <property name="receives-default">True</property>
605 <property name="tooltip-text" translatable="yes">Add Directory</property>
606 <child>
607 <object class="GtkImage">
608 <property name="visible">True</property>
609 <property name="can-focus">False</property>
610 <property name="icon-name">folder-new-symbolic</property>
611 </object>
612 </child>
613 </object>
614 <packing>
615 <property name="expand">False</property>
616 <property name="fill">True</property>
617 <property name="position">2</property>
618 </packing>
619 </child>
620 <child>
621 <object class="GtkButton" id="remote_refresh_button">
622 <property name="name">remote_refresh_button</property>
623 <property name="visible">True</property>
624 <property name="can-focus">True</property>
625 <property name="receives-default">True</property>
626 <property name="tooltip-text" translatable="yes">Refresh Directory</property>
627 <child>
628 <object class="GtkImage">
629 <property name="visible">True</property>
630 <property name="can-focus">False</property>
631 <property name="icon-name">view-refresh-symbolic</property>
632 </object>
633 </child>
634 </object>
635 <packing>
636 <property name="expand">False</property>
637 <property name="fill">True</property>
638 <property name="position">3</property>
639 </packing>
640 </child>
641 </object>
642 <packing>
643 <property name="expand">False</property>
644 <property name="fill">True</property>
645 <property name="position">0</property>
646 </packing>
647 </child>
648 <child>
649 <object class="GtkScrolledWindow">
650 <property name="width-request">400</property>
651 <property name="height-request">200</property>
652 <property name="visible">True</property>
653 <property name="can-focus">True</property>
654 <property name="hexpand">True</property>
655 <property name="vexpand">True</property>
656 <property name="shadow-type">in</property>
657 <child>
658 <object class="GtkTreeView" id="remote_tree_view">
659 <property name="name">remote_tree_view</property>
660 <property name="visible">True</property>
661 <property name="can-focus">True</property>
662 <property name="hexpand">True</property>
663 <property name="vexpand">True</property>
664 <property name="model">remote_list_store</property>
665 <property name="search-column">1</property>
666 <child internal-child="selection">
667 <object class="GtkTreeSelection">
668 <property name="mode">multiple</property>
669 </object>
670 </child>
671 <child>
672 <object class="GtkTreeViewColumn">
673 <child>
674 <object class="GtkCellRendererPixbuf"/>
675 <attributes>
676 <attribute name="icon-name">0</attribute>
677 </attributes>
678 </child>
679 </object>
680 </child>
681 <child>
682 <object class="GtkTreeViewColumn" id="remote_tree_view_index_column">
683 <child>
684 <object class="GtkCellRendererText"/>
685 <attributes>
686 <attribute name="text">5</attribute>
687 </attributes>
688 </child>
689 </object>
690 </child>
691 <child>
692 <object class="GtkTreeViewColumn">
693 <property name="title" translatable="yes">Name</property>
694 <property name="expand">True</property>
695 <child>
696 <object class="GtkCellRendererText" id="remote_name_cell_renderer_text">
697 <property name="ellipsize">middle</property>
698 </object>
699 <attributes>
700 <attribute name="text">1</attribute>
701 </attributes>
702 </child>
703 </object>
704 </child>
705 <child>
706 <object class="GtkTreeViewColumn">
707 <property name="title" translatable="yes">Size</property>
708 <child>
709 <object class="GtkCellRendererText"/>
710 <attributes>
711 <attribute name="text">3</attribute>
712 </attributes>
713 </child>
714 </object>
715 </child>
716 </object>
717 </child>
718 </object>
719 <packing>
720 <property name="expand">False</property>
721 <property name="fill">True</property>
722 <property name="position">1</property>
723 </packing>
724 </child>
725 </object>
726 <packing>
727 <property name="left-attach">1</property>
728 <property name="top-attach">1</property>
729 </packing>
730 </child>
731 <child>
732 <object class="GtkBox">
733 <property name="visible">True</property>
734 <property name="can-focus">False</property>
735 <property name="spacing">6</property>
736 <child>
737 <object class="GtkComboBox" id="devices_combo">
738 <property name="visible">True</property>
739 <property name="can-focus">False</property>
740431 <property name="model">devices_list_store</property>
741432 <child>
742433 <object class="GtkCellRendererText"/>
746437 </child>
747438 </object>
748439 <packing>
749 <property name="expand">True</property>
440 <property name="expand">False</property>
750441 <property name="fill">True</property>
751442 <property name="position">0</property>
752443 </packing>
826517 <packing>
827518 <property name="left-attach">0</property>
828519 <property name="top-attach">0</property>
520 </packing>
521 </child>
522 <child>
523 <object class="GtkBox" id="remote_box">
524 <property name="visible">True</property>
525 <property name="can-focus">False</property>
526 <property name="hexpand">True</property>
527 <property name="vexpand">True</property>
528 <property name="orientation">vertical</property>
529 <property name="spacing">6</property>
530 <child>
531 <object class="GtkBox">
532 <property name="visible">True</property>
533 <property name="can-focus">False</property>
534 <property name="hexpand">True</property>
535 <property name="spacing">6</property>
536 <child>
537 <object class="GtkEntry" id="remote_dir_entry">
538 <property name="visible">True</property>
539 <property name="can-focus">True</property>
540 <property name="hexpand">True</property>
541 <property name="editable">False</property>
542 </object>
543 <packing>
544 <property name="expand">False</property>
545 <property name="fill">True</property>
546 <property name="position">0</property>
547 </packing>
548 </child>
549 <child>
550 <object class="GtkButton" id="remote_up_button">
551 <property name="name">remote_up_button</property>
552 <property name="visible">True</property>
553 <property name="can-focus">True</property>
554 <property name="receives-default">True</property>
555 <property name="tooltip-text" translatable="yes">Go to Parent Directory</property>
556 <child>
557 <object class="GtkImage">
558 <property name="visible">True</property>
559 <property name="can-focus">False</property>
560 <property name="icon-name">go-up-symbolic</property>
561 </object>
562 </child>
563 </object>
564 <packing>
565 <property name="expand">False</property>
566 <property name="fill">True</property>
567 <property name="position">1</property>
568 </packing>
569 </child>
570 <child>
571 <object class="GtkButton" id="remote_add_dir_button">
572 <property name="name">remote_up_button</property>
573 <property name="visible">True</property>
574 <property name="can-focus">True</property>
575 <property name="receives-default">True</property>
576 <property name="tooltip-text" translatable="yes">Add Directory</property>
577 <child>
578 <object class="GtkImage">
579 <property name="visible">True</property>
580 <property name="can-focus">False</property>
581 <property name="icon-name">folder-new-symbolic</property>
582 </object>
583 </child>
584 </object>
585 <packing>
586 <property name="expand">False</property>
587 <property name="fill">True</property>
588 <property name="position">2</property>
589 </packing>
590 </child>
591 <child>
592 <object class="GtkButton" id="remote_refresh_button">
593 <property name="name">remote_refresh_button</property>
594 <property name="visible">True</property>
595 <property name="can-focus">True</property>
596 <property name="receives-default">True</property>
597 <property name="tooltip-text" translatable="yes">Refresh Directory</property>
598 <child>
599 <object class="GtkImage">
600 <property name="visible">True</property>
601 <property name="can-focus">False</property>
602 <property name="icon-name">view-refresh-symbolic</property>
603 </object>
604 </child>
605 </object>
606 <packing>
607 <property name="expand">False</property>
608 <property name="fill">True</property>
609 <property name="position">3</property>
610 </packing>
611 </child>
612 </object>
613 <packing>
614 <property name="expand">False</property>
615 <property name="fill">True</property>
616 <property name="position">0</property>
617 </packing>
618 </child>
619 <child>
620 <object class="GtkStack" id="remote_stack">
621 <property name="visible">True</property>
622 <property name="can-focus">False</property>
623 <child>
624 <object class="GtkScrolledWindow">
625 <property name="width-request">400</property>
626 <property name="height-request">200</property>
627 <property name="visible">True</property>
628 <property name="can-focus">True</property>
629 <property name="hexpand">True</property>
630 <property name="vexpand">True</property>
631 <property name="shadow-type">in</property>
632 <child>
633 <object class="GtkTreeView" id="remote_tree_view">
634 <property name="name">remote_tree_view</property>
635 <property name="visible">True</property>
636 <property name="can-focus">True</property>
637 <property name="hexpand">True</property>
638 <property name="vexpand">True</property>
639 <property name="model">remote_list_store</property>
640 <property name="search-column">1</property>
641 <child internal-child="selection">
642 <object class="GtkTreeSelection">
643 <property name="mode">multiple</property>
644 </object>
645 </child>
646 <child>
647 <object class="GtkTreeViewColumn">
648 <child>
649 <object class="GtkCellRendererPixbuf"/>
650 <attributes>
651 <attribute name="icon-name">0</attribute>
652 </attributes>
653 </child>
654 </object>
655 </child>
656 <child>
657 <object class="GtkTreeViewColumn" id="remote_tree_view_id_column">
658 <property name="visible">False</property>
659 <child>
660 <object class="GtkCellRendererText"/>
661 <attributes>
662 <attribute name="text">5</attribute>
663 </attributes>
664 </child>
665 </object>
666 </child>
667 <child>
668 <object class="GtkTreeViewColumn" id="remote_tree_view_slot_column">
669 <property name="visible">False</property>
670 <child>
671 <object class="GtkCellRendererText"/>
672 <attributes>
673 <attribute name="text">6</attribute>
674 </attributes>
675 </child>
676 </object>
677 </child>
678 <child>
679 <object class="GtkTreeViewColumn">
680 <property name="title" translatable="yes">Name</property>
681 <property name="expand">True</property>
682 <child>
683 <object class="GtkCellRendererText" id="remote_name_cell_renderer_text">
684 <property name="ellipsize">middle</property>
685 </object>
686 <attributes>
687 <attribute name="text">1</attribute>
688 </attributes>
689 </child>
690 </object>
691 </child>
692 <child>
693 <object class="GtkTreeViewColumn" id="remote_tree_view_size_column">
694 <property name="visible">False</property>
695 <property name="title" translatable="yes">Size</property>
696 <child>
697 <object class="GtkCellRendererText"/>
698 <attributes>
699 <attribute name="text">3</attribute>
700 </attributes>
701 </child>
702 </object>
703 </child>
704 </object>
705 </child>
706 </object>
707 <packing>
708 <property name="name">list</property>
709 </packing>
710 </child>
711 <child>
712 <object class="GtkFrame">
713 <property name="visible">True</property>
714 <property name="can-focus">False</property>
715 <property name="label-xalign">0</property>
716 <child>
717 <object class="GtkAlignment">
718 <property name="visible">True</property>
719 <property name="can-focus">False</property>
720 <property name="left-padding">12</property>
721 <child>
722 <object class="GtkSpinner" id="remote_spinner">
723 <property name="visible">True</property>
724 <property name="can-focus">False</property>
725 </object>
726 </child>
727 </object>
728 </child>
729 <child type="label_item">
730 <placeholder/>
731 </child>
732 </object>
733 <packing>
734 <property name="name">spinner</property>
735 <property name="position">1</property>
736 </packing>
737 </child>
738 </object>
739 <packing>
740 <property name="expand">False</property>
741 <property name="fill">True</property>
742 <property name="position">1</property>
743 </packing>
744 </child>
745 </object>
746 <packing>
747 <property name="left-attach">1</property>
748 <property name="top-attach">1</property>
749 </packing>
750 </child>
751 <child>
752 <object class="GtkBox" id="local_box">
753 <property name="visible">True</property>
754 <property name="can-focus">False</property>
755 <property name="hexpand">True</property>
756 <property name="vexpand">True</property>
757 <property name="orientation">vertical</property>
758 <property name="spacing">6</property>
759 <child>
760 <object class="GtkBox">
761 <property name="visible">True</property>
762 <property name="can-focus">False</property>
763 <property name="hexpand">True</property>
764 <property name="spacing">6</property>
765 <child>
766 <object class="GtkEntry" id="local_dir_entry">
767 <property name="visible">True</property>
768 <property name="can-focus">True</property>
769 <property name="hexpand">True</property>
770 <property name="editable">False</property>
771 </object>
772 <packing>
773 <property name="expand">False</property>
774 <property name="fill">True</property>
775 <property name="position">0</property>
776 </packing>
777 </child>
778 <child>
779 <object class="GtkButton" id="local_up_button">
780 <property name="name">local_up_button</property>
781 <property name="visible">True</property>
782 <property name="can-focus">True</property>
783 <property name="receives-default">True</property>
784 <property name="tooltip-text" translatable="yes">Go to Parent Directory</property>
785 <child>
786 <object class="GtkImage">
787 <property name="visible">True</property>
788 <property name="can-focus">False</property>
789 <property name="icon-name">go-up-symbolic</property>
790 </object>
791 </child>
792 </object>
793 <packing>
794 <property name="expand">False</property>
795 <property name="fill">True</property>
796 <property name="position">1</property>
797 </packing>
798 </child>
799 <child>
800 <object class="GtkButton" id="local_add_dir_button">
801 <property name="name">local_up_button</property>
802 <property name="visible">True</property>
803 <property name="can-focus">True</property>
804 <property name="receives-default">True</property>
805 <property name="tooltip-text" translatable="yes">Add Directory</property>
806 <child>
807 <object class="GtkImage">
808 <property name="visible">True</property>
809 <property name="can-focus">False</property>
810 <property name="icon-name">folder-new-symbolic</property>
811 </object>
812 </child>
813 </object>
814 <packing>
815 <property name="expand">False</property>
816 <property name="fill">True</property>
817 <property name="position">2</property>
818 </packing>
819 </child>
820 <child>
821 <object class="GtkButton" id="local_refresh_button">
822 <property name="name">local_refresh_button</property>
823 <property name="visible">True</property>
824 <property name="can-focus">True</property>
825 <property name="receives-default">True</property>
826 <property name="tooltip-text" translatable="yes">Refresh Directory</property>
827 <child>
828 <object class="GtkImage">
829 <property name="visible">True</property>
830 <property name="can-focus">False</property>
831 <property name="icon-name">view-refresh-symbolic</property>
832 </object>
833 </child>
834 </object>
835 <packing>
836 <property name="expand">False</property>
837 <property name="fill">True</property>
838 <property name="position">3</property>
839 </packing>
840 </child>
841 </object>
842 <packing>
843 <property name="expand">False</property>
844 <property name="fill">True</property>
845 <property name="position">0</property>
846 </packing>
847 </child>
848 <child>
849 <object class="GtkStack" id="local_stack">
850 <property name="visible">True</property>
851 <property name="can-focus">False</property>
852 <child>
853 <object class="GtkScrolledWindow">
854 <property name="width-request">400</property>
855 <property name="height-request">200</property>
856 <property name="visible">True</property>
857 <property name="can-focus">True</property>
858 <property name="hexpand">True</property>
859 <property name="vexpand">True</property>
860 <property name="shadow-type">in</property>
861 <child>
862 <object class="GtkTreeView" id="local_tree_view">
863 <property name="name">local_tree_view</property>
864 <property name="visible">True</property>
865 <property name="can-focus">True</property>
866 <property name="hexpand">True</property>
867 <property name="vexpand">True</property>
868 <property name="model">local_list_store</property>
869 <property name="search-column">1</property>
870 <child internal-child="selection">
871 <object class="GtkTreeSelection">
872 <property name="mode">multiple</property>
873 </object>
874 </child>
875 <child>
876 <object class="GtkTreeViewColumn">
877 <child>
878 <object class="GtkCellRendererPixbuf"/>
879 <attributes>
880 <attribute name="icon-name">0</attribute>
881 </attributes>
882 </child>
883 </object>
884 </child>
885 <child>
886 <object class="GtkTreeViewColumn">
887 <property name="title" translatable="yes">Name</property>
888 <property name="expand">True</property>
889 <child>
890 <object class="GtkCellRendererText">
891 <property name="ellipsize">middle</property>
892 </object>
893 <attributes>
894 <attribute name="text">1</attribute>
895 </attributes>
896 </child>
897 </object>
898 </child>
899 <child>
900 <object class="GtkTreeViewColumn">
901 <property name="title" translatable="yes">Size</property>
902 <child>
903 <object class="GtkCellRendererText"/>
904 <attributes>
905 <attribute name="text">3</attribute>
906 </attributes>
907 </child>
908 </object>
909 </child>
910 </object>
911 </child>
912 </object>
913 <packing>
914 <property name="name">list</property>
915 </packing>
916 </child>
917 <child>
918 <object class="GtkFrame">
919 <property name="visible">True</property>
920 <property name="can-focus">False</property>
921 <property name="label-xalign">0</property>
922 <child>
923 <object class="GtkAlignment">
924 <property name="visible">True</property>
925 <property name="can-focus">False</property>
926 <property name="left-padding">12</property>
927 <child>
928 <object class="GtkSpinner" id="local_spinner">
929 <property name="visible">True</property>
930 <property name="can-focus">False</property>
931 </object>
932 </child>
933 </object>
934 </child>
935 <child type="label_item">
936 <placeholder/>
937 </child>
938 </object>
939 <packing>
940 <property name="name">spinner</property>
941 <property name="position">1</property>
942 </packing>
943 </child>
944 </object>
945 <packing>
946 <property name="expand">False</property>
947 <property name="fill">True</property>
948 <property name="position">1</property>
949 </packing>
950 </child>
951 </object>
952 <packing>
953 <property name="left-attach">0</property>
954 <property name="top-attach">1</property>
829955 </packing>
830956 </child>
831957 </object>
847973 <property name="visible">True</property>
848974 <property name="can-focus">False</property>
849975 <property name="halign">start</property>
850 <property name="valign">center</property>
976 <property name="valign">start</property>
851977 <property name="orientation">vertical</property>
852978 <property name="spacing">12</property>
853979 <child>
8891015 <property name="expand">False</property>
8901016 <property name="fill">True</property>
8911017 <property name="position">0</property>
1018 </packing>
1019 </child>
1020 <child>
1021 <object class="GtkBox">
1022 <property name="visible">True</property>
1023 <property name="can-focus">False</property>
1024 <property name="spacing">6</property>
1025 <child>
1026 <object class="GtkSwitch" id="mix_switch">
1027 <property name="name">autoplay_switch</property>
1028 <property name="visible">True</property>
1029 <property name="can-focus">True</property>
1030 <property name="halign">start</property>
1031 <property name="valign">center</property>
1032 <property name="active">True</property>
1033 </object>
1034 <packing>
1035 <property name="expand">False</property>
1036 <property name="fill">True</property>
1037 <property name="position">0</property>
1038 </packing>
1039 </child>
1040 <child>
1041 <object class="GtkLabel">
1042 <property name="visible">True</property>
1043 <property name="can-focus">False</property>
1044 <property name="tooltip-text" translatable="yes">Playing mix depends on the destination channels</property>
1045 <property name="valign">center</property>
1046 <property name="label" translatable="yes" comments="It is recommended to split the text in two lines if it is too long">Mix depending
1047 on destination</property>
1048 <property name="wrap">True</property>
1049 </object>
1050 <packing>
1051 <property name="expand">False</property>
1052 <property name="fill">True</property>
1053 <property name="position">1</property>
1054 </packing>
1055 </child>
1056 </object>
1057 <packing>
1058 <property name="expand">False</property>
1059 <property name="fill">True</property>
1060 <property name="position">1</property>
8921061 </packing>
8931062 </child>
8941063 <child>
10071176 <property name="relief">none</property>
10081177 </object>
10091178 </child>
1010 <style>
1011 <class name="local"/>
1012 </style>
10131179 </object>
10141180 <packing>
10151181 <property name="expand">False</property>
10211187 <packing>
10221188 <property name="expand">False</property>
10231189 <property name="fill">True</property>
1024 <property name="position">1</property>
1190 <property name="position">2</property>
10251191 </packing>
10261192 </child>
10271193 </object>
10351201 <object class="GtkFrame">
10361202 <property name="visible">True</property>
10371203 <property name="can-focus">False</property>
1204 <property name="vexpand">True</property>
10381205 <property name="label-xalign">0</property>
10391206 <child>
10401207 <object class="GtkDrawingArea" id="waveform_draw_area">
10411208 <property name="visible">True</property>
10421209 <property name="can-focus">False</property>
10431210 <property name="hexpand">True</property>
1044 <style>
1045 <class name="local"/>
1046 <class name="waveform"/>
1047 </style>
10481211 </object>
10491212 </child>
10501213 <child type="label_item">
10551218 <property name="expand">True</property>
10561219 <property name="fill">True</property>
10571220 <property name="position">1</property>
1221 </packing>
1222 </child>
1223 <child>
1224 <!-- n-columns=2 n-rows=5 -->
1225 <object class="GtkGrid" id="sample_info_box">
1226 <property name="visible">True</property>
1227 <property name="can-focus">False</property>
1228 <property name="row-spacing">6</property>
1229 <property name="column-spacing">6</property>
1230 <child>
1231 <object class="GtkLabel">
1232 <property name="visible">True</property>
1233 <property name="can-focus">False</property>
1234 <property name="halign">end</property>
1235 <property name="valign">center</property>
1236 <property name="label" translatable="yes">Samples</property>
1237 <property name="wrap">True</property>
1238 </object>
1239 <packing>
1240 <property name="left-attach">0</property>
1241 <property name="top-attach">0</property>
1242 </packing>
1243 </child>
1244 <child>
1245 <object class="GtkLabel">
1246 <property name="visible">True</property>
1247 <property name="can-focus">False</property>
1248 <property name="halign">end</property>
1249 <property name="valign">center</property>
1250 <property name="label" translatable="yes">Channels</property>
1251 <property name="wrap">True</property>
1252 </object>
1253 <packing>
1254 <property name="left-attach">0</property>
1255 <property name="top-attach">3</property>
1256 </packing>
1257 </child>
1258 <child>
1259 <object class="GtkLabel">
1260 <property name="visible">True</property>
1261 <property name="can-focus">False</property>
1262 <property name="halign">end</property>
1263 <property name="valign">center</property>
1264 <property name="label" translatable="yes">Sample rate</property>
1265 <property name="wrap">True</property>
1266 </object>
1267 <packing>
1268 <property name="left-attach">0</property>
1269 <property name="top-attach">2</property>
1270 </packing>
1271 </child>
1272 <child>
1273 <object class="GtkLabel">
1274 <property name="visible">True</property>
1275 <property name="can-focus">False</property>
1276 <property name="halign">end</property>
1277 <property name="valign">center</property>
1278 <property name="label" translatable="yes">Bit depth</property>
1279 <property name="wrap">True</property>
1280 </object>
1281 <packing>
1282 <property name="left-attach">0</property>
1283 <property name="top-attach">4</property>
1284 </packing>
1285 </child>
1286 <child>
1287 <object class="GtkLabel" id="sample_length">
1288 <property name="visible">True</property>
1289 <property name="can-focus">False</property>
1290 <property name="halign">start</property>
1291 </object>
1292 <packing>
1293 <property name="left-attach">1</property>
1294 <property name="top-attach">0</property>
1295 </packing>
1296 </child>
1297 <child>
1298 <object class="GtkLabel" id="sample_channels">
1299 <property name="visible">True</property>
1300 <property name="can-focus">False</property>
1301 <property name="halign">start</property>
1302 </object>
1303 <packing>
1304 <property name="left-attach">1</property>
1305 <property name="top-attach">3</property>
1306 </packing>
1307 </child>
1308 <child>
1309 <object class="GtkLabel" id="sample_samplerate">
1310 <property name="visible">True</property>
1311 <property name="can-focus">False</property>
1312 <property name="halign">start</property>
1313 </object>
1314 <packing>
1315 <property name="left-attach">1</property>
1316 <property name="top-attach">2</property>
1317 </packing>
1318 </child>
1319 <child>
1320 <object class="GtkLabel" id="sample_bitdepth">
1321 <property name="visible">True</property>
1322 <property name="can-focus">False</property>
1323 <property name="halign">start</property>
1324 </object>
1325 <packing>
1326 <property name="left-attach">1</property>
1327 <property name="top-attach">4</property>
1328 </packing>
1329 </child>
1330 <child>
1331 <object class="GtkLabel">
1332 <property name="visible">True</property>
1333 <property name="can-focus">False</property>
1334 <property name="halign">end</property>
1335 <property name="valign">center</property>
1336 <property name="label" translatable="yes">Duration</property>
1337 <property name="wrap">True</property>
1338 </object>
1339 <packing>
1340 <property name="left-attach">0</property>
1341 <property name="top-attach">1</property>
1342 </packing>
1343 </child>
1344 <child>
1345 <object class="GtkLabel" id="sample_duration">
1346 <property name="visible">True</property>
1347 <property name="can-focus">False</property>
1348 <property name="halign">start</property>
1349 </object>
1350 <packing>
1351 <property name="left-attach">1</property>
1352 <property name="top-attach">1</property>
1353 </packing>
1354 </child>
1355 </object>
1356 <packing>
1357 <property name="expand">False</property>
1358 <property name="fill">True</property>
1359 <property name="position">2</property>
10581360 </packing>
10591361 </child>
10601362 </object>
13121614 <property name="resizable">False</property>
13131615 <property name="modal">True</property>
13141616 <property name="type-hint">dialog</property>
1617 <property name="deletable">False</property>
13151618 <property name="transient-for">main_window</property>
13161619 <child internal-child="vbox">
13171620 <object class="GtkBox">
13871690 <property name="can-focus">True</property>
13881691 <property name="is-focus">True</property>
13891692 <property name="hexpand">True</property>
1390 <property name="max-length">32</property>
13911693 <property name="activates-default">True</property>
13921694 <property name="input-purpose">alpha</property>
13931695 </object>
14121714 <property name="resizable">False</property>
14131715 <property name="modal">True</property>
14141716 <property name="type-hint">dialog</property>
1717 <property name="deletable">False</property>
14151718 <property name="transient-for">main_window</property>
14161719 <child internal-child="vbox">
14171720 <object class="GtkBox">
00 PKG_CONFIG ?= pkg-config
11
2 GUI_LIBS = alsa gtk+-3.0 libpulse libpulse-mainloop-glib zlib json-glib-1.0 libzip
32 CLI_LIBS = alsa glib-2.0 zlib json-glib-1.0 libzip
3 GUI_LIBS = $(CLI_LIBS) gtk+-3.0 libpulse libpulse-mainloop-glib
44
55 elektroid_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(GUI_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS) -D_GNU_SOURCE
66 elektroid_LDFLAGS = `$(PKG_CONFIG) --libs $(GUI_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS)
1313 bin_PROGRAMS = elektroid elektroid-cli
1414 endif
1515
16 elektroid_SOURCES = audio.c audio.h browser.c browser.h connector.c connector.h elektroid.c sample.c sample.h utils.c utils.h notifier.c notifier.h local.c local.h preferences.c preferences.h utils.h package.c package.h
17 elektroid_cli_SOURCES = connector.c connector.h elektroid-cli.c sample.c sample.h utils.c utils.h package.c package.h
16 elektroid_common_sources = local.c local.h connector.c connector.h \
17 sample.c sample.h utils.c utils.h backend.c backend.h \
18 connectors/common.c connectors/common.h \
19 connectors/elektron.c connectors/elektron.h connectors/package.c connectors/package.h \
20 connectors/microbrute.c connectors/microbrute.h \
21 connectors/cz.c connectors/cz.h \
22 connectors/sds.c connectors/sds.h \
23 connectors/efactor.c connectors/efactor.h
24
25 elektroid_cli_SOURCES = $(elektroid_common_sources) elektroid-cli.c
26
27 elektroid_SOURCES = $(elektroid_common_sources) audio.c audio.h \
28 browser.c browser.h notifier.c notifier.h \
29 preferences.c preferences.h elektroid.c
1830
1931 SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
2032 SNDFILE_LIBS = @SNDFILE_LIBS@
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #include "../config.h"
2120 #include "audio.h"
2221
23 #define PA_BUFFER_LEN 4800
24 #define CHANNELS 1
22 #define AUDIO_PA_BUFFER_LEN (AUDIO_SAMPLE_RATE / 10)
23 #define AUDIO_CHANNELS 2
2524
2625 static const pa_buffer_attr buffer_attributes = {
2726 .maxlength = -1,
28 .tlength = PA_BUFFER_LEN * 2,
27 .tlength = AUDIO_PA_BUFFER_LEN * 2,
2928 .prebuf = 0,
3029 .minreq = -1
3130 };
3231
3332 static const pa_sample_spec sample_spec = {
3433 .format = PA_SAMPLE_S16LE,
35 .channels = CHANNELS,
36 .rate = 48000
34 .channels = AUDIO_CHANNELS,
35 .rate = AUDIO_SAMPLE_RATE
3736 };
3837
3938 static void
39 audio_success_cb (pa_stream * stream, int success, void *data)
40 {
41 struct audio *audio = data;
42 pa_threaded_mainloop_signal (audio->mainloop, 0);
43 }
44
45 static void
46 audio_wait_success (struct audio *audio, pa_operation * operation)
47 {
48 if (!operation)
49 {
50 debug_print (2, "No operation. Skipping wait...\n");
51 return;
52 }
53 while (pa_operation_get_state (operation) != PA_OPERATION_DONE)
54 {
55 pa_threaded_mainloop_wait (audio->mainloop);
56 }
57 }
58
59 static void
4060 audio_write_callback (pa_stream * stream, size_t size, void *data)
4161 {
4262 struct audio *audio = data;
43 guint req_frames;
63 guint32 req_frames;
4464 void *buffer;
45 gshort *v;
46 gint i;
47
48 if (audio->release_frames > PA_BUFFER_LEN)
65 gint16 *dst, *src;
66
67 if (audio->release_frames > AUDIO_PA_BUFFER_LEN)
4968 {
5069 pa_stream_cork (audio->stream, 1, NULL, NULL);
5170 return;
5271 }
5372
54 req_frames = size >> 1;
55 debug_print (2, "Writing %2d frames...\n", req_frames);
73 req_frames = size >> AUDIO_CHANNELS;
74
5675 pa_stream_begin_write (stream, &buffer, &size);
5776
5877 g_mutex_lock (&audio->control.mutex);
5978
60 if (!audio->sample->len)
79 debug_print (2, "Writing %d frames to %d channels...\n", req_frames,
80 audio->channels);
81
82 if (!audio->sample || !audio->sample->len)
6183 {
6284 g_mutex_unlock (&audio->control.mutex);
6385 pa_stream_cancel_write (stream);
64 debug_print (2, "Canceled\n");
65 return;
66 }
67
68 if (audio->pos == audio->sample->len >> 1 && !audio->loop)
69 {
70 g_mutex_unlock (&audio->control.mutex);
71 memset (buffer, 0, size);
86 debug_print (2, "Cancelled\n");
87 return;
88 }
89
90 memset (buffer, 0, size);
91
92 if ((audio->pos == audio->frames && !audio->loop) ||
93 audio->status == AUDIO_STATUS_PREPARING ||
94 audio->status == AUDIO_STATUS_STOPPING)
95 {
96 if (audio->status == AUDIO_STATUS_PREPARING)
97 {
98 audio->status = AUDIO_STATUS_PLAYING;
99 g_mutex_unlock (&audio->control.mutex);
100 }
101 else
102 {
103 g_mutex_unlock (&audio->control.mutex);
104 audio->release_frames += req_frames;
105 }
72106 pa_stream_write (stream, buffer, size, NULL, 0, PA_SEEK_RELATIVE);
73 audio->release_frames += req_frames;
74 return;
75 }
76
77 v = buffer;
78 for (i = 0; i < req_frames; i++)
79 {
80 if (audio->pos < audio->sample->len >> 1)
81 {
82 *v = ((short *) audio->sample->data)[audio->pos];
83 audio->pos++;
84 }
85 else
86 {
87 if (audio->loop)
88 {
89 audio->pos = 0;
90 *v = ((short *) audio->sample->data)[0];
91 }
92 else
107 return;
108 }
109
110 dst = buffer;
111 src = (gint16 *) & audio->sample->data[audio->pos << audio->channels];
112 for (gint i = 0; i < req_frames; i++)
113 {
114 if (audio->pos == audio->frames)
115 {
116 if (!audio->loop)
93117 {
94118 break;
95119 }
96 }
97 v++;
120 debug_print (2, "Sample reset\n");
121 audio->pos = 0;
122 src = (gint16 *) audio->sample->data;
123 }
124
125 *dst = *src;
126 dst++;
127 if (audio->channels == 2)
128 {
129 src++;
130 }
131 *dst = *src;
132 src++;
133 dst++;
134 audio->pos++;
98135 }
99136
100137 g_mutex_unlock (&audio->control.mutex);
101138
102 pa_stream_write (stream, buffer, i * 2, NULL, 0, PA_SEEK_RELATIVE);
139 pa_stream_write (stream, buffer, size, NULL, 0, PA_SEEK_RELATIVE);
103140 }
104141
105142 void
112149 return;
113150 }
114151
115 debug_print (1, "Stopping audio...\n");
116
117 pa_threaded_mainloop_lock (audio->mainloop);
118 if (flush)
119 {
120 operation = pa_stream_flush (audio->stream, NULL, NULL);
121 if (operation != NULL)
122 {
123 pa_operation_unref (operation);
124 }
125 }
126
127 operation = pa_stream_cork (audio->stream, 1, NULL, NULL);
128 if (operation != NULL)
129 {
130 pa_operation_unref (operation);
131 }
132 pa_threaded_mainloop_unlock (audio->mainloop);
152 g_mutex_lock (&audio->control.mutex);
153 if (audio->status == AUDIO_STATUS_PREPARING ||
154 audio->status == AUDIO_STATUS_PLAYING)
155 {
156 audio->status = AUDIO_STATUS_STOPPING;
157 g_mutex_unlock (&audio->control.mutex);
158
159 debug_print (1, "Stopping audio...\n");
160
161 pa_threaded_mainloop_lock (audio->mainloop);
162 if (flush)
163 {
164 operation =
165 pa_stream_flush (audio->stream, audio_success_cb, audio);
166 audio_wait_success (audio, operation);
167 }
168
169 operation = pa_stream_cork (audio->stream, 1, audio_success_cb, audio);
170 audio_wait_success (audio, operation);
171 pa_threaded_mainloop_unlock (audio->mainloop);
172
173 g_mutex_lock (&audio->control.mutex);
174 audio->status = AUDIO_STATUS_STOPPED;
175 g_mutex_unlock (&audio->control.mutex);
176 }
177 else
178 {
179 while (audio->status != AUDIO_STATUS_STOPPED)
180 {
181 g_mutex_unlock (&audio->control.mutex);
182 usleep (100000);
183 g_mutex_lock (&audio->control.mutex);
184 }
185 g_mutex_unlock (&audio->control.mutex);
186 }
133187 }
134188
135189 void
149203 g_mutex_lock (&audio->control.mutex);
150204 audio->pos = 0;
151205 audio->release_frames = 0;
206 audio->status = AUDIO_STATUS_PREPARING;
152207 g_mutex_unlock (&audio->control.mutex);
153208
154209 pa_threaded_mainloop_lock (audio->mainloop);
155 operation = pa_stream_cork (audio->stream, 0, NULL, NULL);
156 if (operation != NULL)
157 {
158 pa_operation_unref (operation);
159 }
210 operation = pa_stream_cork (audio->stream, 0, audio_success_cb, audio);
211 audio_wait_success (audio, operation);
160212 pa_threaded_mainloop_unlock (audio->mainloop);
161213 }
162214
169221 if (info && pa_cvolume_valid (&info->volume))
170222 {
171223 gdouble v = pa_sw_volume_to_linear (pa_cvolume_avg (&info->volume));
224 debug_print (1, "Setting volume to %f...\n", v);
172225 audio->volume_change_callback (v);
173226 }
174227 }
228281 pa_proplist_set (props,
229282 PA_PROP_APPLICATION_ICON_NAME,
230283 PACKAGE, sizeof (PACKAGE));
231 audio->stream =
232 pa_stream_new_with_proplist (context, PACKAGE, &sample_spec, NULL,
233 props);
284 audio->stream = pa_stream_new_with_proplist (context, PACKAGE,
285 &sample_spec, NULL, props);
234286 pa_proplist_free (props);
235287 pa_stream_set_state_callback (audio->stream, audio_connect_callback,
236288 audio);
237289 pa_stream_connect_playback (audio->stream, NULL, &buffer_attributes,
238290 stream_flags, NULL, NULL);
239291 pa_context_set_subscribe_callback (audio->context, audio_notify, audio);
240 operation =
241 pa_context_subscribe (audio->context,
242 PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, NULL);
292 operation = pa_context_subscribe (audio->context,
293 PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL,
294 NULL);
243295 if (operation != NULL)
244296 {
245297 pa_operation_unref (operation);
247299 }
248300 }
249301
250 gint
302 void
251303 audio_init (struct audio *audio, void (*volume_change_callback) (gdouble),
252 void (*load_progress_callback) (gdouble))
253 {
254 pa_mainloop_api *api;
255 gint err = 0;
256
304 job_control_callback load_progress_callback)
305 {
257306 debug_print (1, "Initializing audio...\n");
258
259307 audio->sample = g_byte_array_new ();
260308 audio->frames = 0;
261309 audio->loop = FALSE;
262 audio->mainloop = pa_threaded_mainloop_new ();
263 api = pa_threaded_mainloop_get_api (audio->mainloop);
264 audio->context = pa_context_new (api, PACKAGE);
265310 audio->stream = NULL;
266311 audio->index = PA_INVALID_INDEX;
267312 audio->volume_change_callback = volume_change_callback;
268313 audio->control.callback = load_progress_callback;
269 audio->name = malloc (PATH_MAX);
270 audio->name[0] = 0;
314 audio->path[0] = 0;
315 audio->control.data = g_malloc (sizeof (struct sample_info));
316 audio->status = AUDIO_STATUS_STOPPED;
317 }
318
319 gint
320 audio_run (struct audio *audio)
321 {
322 pa_mainloop_api *api;
323 audio->mainloop = pa_threaded_mainloop_new ();
324 if (!audio->mainloop)
325 {
326 return -1;
327 }
328
329 api = pa_threaded_mainloop_get_api (audio->mainloop);
330 audio->context = pa_context_new (api, PACKAGE);
271331
272332 if (pa_context_connect (audio->context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
273333 {
274334 pa_context_unref (audio->context);
275335 pa_threaded_mainloop_free (audio->mainloop);
276336 audio->mainloop = NULL;
277 err = -1;
337 return -1;
278338 }
279339 else
280340 {
281341 pa_context_set_state_callback (audio->context, audio_context_callback,
282342 audio);
283343 pa_threaded_mainloop_start (audio->mainloop);
284
285
286 }
287
288 return err;
344 pa_threaded_mainloop_wait (audio->mainloop);
345 }
346
347 return 0;
289348 }
290349
291350 void
294353 debug_print (1, "Destroying audio...\n");
295354
296355 audio_stop (audio, TRUE);
297
298 g_byte_array_free (audio->sample, TRUE);
299 if (audio->stream)
300 {
301 pa_stream_unref (audio->stream);
302 audio->stream = NULL;
303 }
356 audio_reset_sample (audio);
357
358 g_mutex_lock (&audio->control.mutex);
304359
305360 if (audio->mainloop)
306361 {
362 pa_threaded_mainloop_stop (audio->mainloop);
363 pa_context_disconnect (audio->context);
307364 pa_context_unref (audio->context);
308 pa_threaded_mainloop_stop (audio->mainloop);
365 if (audio->stream)
366 {
367 pa_stream_unref (audio->stream);
368 audio->stream = NULL;
369 }
309370 pa_threaded_mainloop_free (audio->mainloop);
310371 audio->mainloop = NULL;
311372 }
312373
313 g_free (audio->name);
374 g_free (audio->control.data);
375 g_byte_array_free (audio->sample, TRUE);
376 audio->sample = NULL;
377
378 g_mutex_unlock (&audio->control.mutex);
314379 }
315380
316381 gboolean
323388 audio_reset_sample (struct audio *audio)
324389 {
325390 g_mutex_lock (&audio->control.mutex);
391 debug_print (1, "Resetting sample...\n");
326392 g_byte_array_set_size (audio->sample, 0);
327393 audio->frames = 0;
328394 audio->pos = 0;
395 audio->path[0] = 0;
396 audio->release_frames = AUDIO_PA_BUFFER_LEN;
397 audio->src = AUDIO_SRC_NONE;
398 audio->status = AUDIO_STATUS_STOPPED;
399 memset (audio->control.data, 0, sizeof (struct sample_info));
329400 g_mutex_unlock (&audio->control.mutex);
330401 }
331402
339410 {
340411 debug_print (1, "Setting volume to %f...\n", volume);
341412 v = pa_sw_volume_from_linear (volume);
342 pa_cvolume_set (&audio->volume, CHANNELS, v);
343
344 operation =
345 pa_context_set_sink_input_volume (audio->context, audio->index,
346 &audio->volume, NULL, NULL);
413 pa_cvolume_set (&audio->volume, AUDIO_CHANNELS, v);
414
415 operation = pa_context_set_sink_input_volume (audio->context,
416 audio->index,
417 &audio->volume, NULL,
418 NULL);
347419 if (operation != NULL)
348420 {
349421 pa_operation_unref (operation);
2121 #include <pulse/pulseaudio.h>
2222 #include "utils.h"
2323
24 enum audio_src
25 {
26 AUDIO_SRC_NONE,
27 AUDIO_SRC_LOCAL,
28 AUDIO_SRC_REMOTE
29 };
30
31 enum audio_status
32 {
33 AUDIO_STATUS_PREPARING,
34 AUDIO_STATUS_PLAYING,
35 AUDIO_STATUS_STOPPING,
36 AUDIO_STATUS_STOPPED
37 };
38
39
2440 struct audio
2541 {
2642 GByteArray *sample;
27 guint frames;
43 guint32 frames;
2844 gboolean loop;
2945 pa_threaded_mainloop *mainloop;
3046 pa_context *context;
3147 pa_stream *stream;
32 gint pos;
48 guint32 pos;
3349 pa_cvolume volume;
34 uint32_t index;
50 guint32 index;
3551 void (*volume_change_callback) (gdouble);
36 gint release_frames;
52 guint32 release_frames;
3753 struct job_control control;
38 gchar *name;
54 gchar path[PATH_MAX];
55 guint32 channels;
56 enum audio_src src;
57 enum audio_status status;
3958 };
4059
4160 void audio_play (struct audio *);
4463
4564 gboolean audio_check (struct audio *);
4665
47 gint audio_init (struct audio *, void (*)(gdouble), void (*)(gdouble));
66 void audio_init (struct audio *, void (*)(gdouble), job_control_callback);
67
68 gint audio_run (struct audio *);
4869
4970 void audio_destroy (struct audio *);
5071
0 /*
1 * backend.c
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "backend.h"
21 #include "local.h"
22
23 #define BE_POLL_TIMEOUT_MS 20
24 #define BE_KB 1024
25 #define BE_MAX_TX_LEN BE_KB //With a higher value than 4 KB, functions behave erratically.
26 #define BE_INT_BUF_LEN (32 * BE_KB) //Max length of a SysEx message for Elektroid
27 #define BE_DEV_RING_BUF_LEN (256 * BE_KB)
28 #define BE_DEVICE_NAME "hw:%d,%d,%d"
29 #define BE_TMP_BUFF_LEN 256
30
31 //Identity Request Universal Sysex message
32 static const guint8 BE_MIDI_IDENTITY_REQUEST[] =
33 { 0xf0, 0x7e, 0x7f, 6, 1, 0xf7 };
34
35 gdouble
36 backend_get_storage_stats_percent (struct backend_storage_stats *statfs)
37 {
38 return (statfs->bsize - statfs->bfree) * 100.0 / statfs->bsize;
39 }
40
41 const struct fs_operations *
42 backend_get_fs_operations (struct backend *backend, gint fs,
43 const gchar * name)
44 {
45 const struct fs_operations **fs_operations = backend->fs_ops;
46 if (!fs_operations)
47 {
48 return NULL;
49 }
50 while (*fs_operations)
51 {
52 const struct fs_operations *ops = *fs_operations;
53 if (ops->fs == fs || (name && !strcmp (ops->name, name)))
54 {
55 return ops;
56 }
57 fs_operations++;
58 }
59 return NULL;
60 }
61
62 void
63 backend_enable_cache (struct backend *backend)
64 {
65 g_mutex_lock (&backend->mutex);
66 if (!backend->cache)
67 {
68 backend->cache = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
69 (GDestroyNotify) g_bytes_unref,
70 (GDestroyNotify) free_msg);
71 }
72 g_mutex_unlock (&backend->mutex);
73 }
74
75 void
76 backend_disable_cache (struct backend *backend)
77 {
78 g_mutex_lock (&backend->mutex);
79 if (backend->cache)
80 {
81 g_hash_table_destroy (backend->cache);
82 backend->cache = NULL;
83 }
84 g_mutex_unlock (&backend->mutex);
85 }
86
87 void
88 backend_destroy (struct backend *backend)
89 {
90 gint err;
91
92 debug_print (1, "Destroying backend...\n");
93
94 backend->device_desc.id = -1;
95 backend->device_desc.filesystems = 0;
96 backend->upgrade_os = NULL;
97 backend->get_storage_stats = NULL;
98 backend->type = BE_TYPE_NONE;
99
100 if (backend->inputp)
101 {
102 err = snd_rawmidi_close (backend->inputp);
103 if (err)
104 {
105 error_print ("Error while closing MIDI port: %s\n",
106 snd_strerror (err));
107 }
108 backend->inputp = NULL;
109 }
110
111 if (backend->outputp)
112 {
113 err = snd_rawmidi_close (backend->outputp);
114 if (err)
115 {
116 error_print ("Error while closing MIDI port: %s\n",
117 snd_strerror (err));
118 }
119 backend->outputp = NULL;
120 }
121
122 if (backend->buffer)
123 {
124 free (backend->buffer);
125 backend->buffer = NULL;
126 }
127
128 if (backend->pfds)
129 {
130 free (backend->pfds);
131 backend->pfds = NULL;
132 }
133
134 if (backend->destroy_data)
135 {
136 backend->destroy_data (backend);
137 }
138
139 backend_disable_cache (backend);
140 }
141
142 static void
143 backend_midi_handshake (struct backend *backend)
144 {
145 GByteArray *tx_msg;
146 GByteArray *rx_msg;
147 gint offset;
148
149 backend->device_desc.id = -1;
150 backend->device_desc.storage = 0;
151 backend->device_desc.name[0] = 0;
152 backend->device_desc.alias[0] = 0;
153 backend->device_name[0] = 0;
154 backend->fs_ops = NULL;
155 backend->destroy_data = NULL;
156 backend->upgrade_os = NULL;
157 backend->get_storage_stats = NULL;
158 memset (&backend->midi_info, 0, sizeof (struct backend_midi_info));
159
160 g_mutex_lock (&backend->mutex);
161 backend_rx_drain (backend);
162 g_mutex_unlock (&backend->mutex);
163
164 tx_msg = g_byte_array_sized_new (sizeof (BE_MIDI_IDENTITY_REQUEST));
165 g_byte_array_append (tx_msg, (guchar *) BE_MIDI_IDENTITY_REQUEST,
166 sizeof (BE_MIDI_IDENTITY_REQUEST));
167 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg,
168 BE_SYSEX_TIMEOUT_GUESS_MS);
169 if (!rx_msg)
170 {
171 debug_print (1, "No MIDI identity reply\n");
172 return;
173 }
174
175 if (rx_msg->data[4] == 2)
176 {
177 if (rx_msg->len == 15 || rx_msg->len == 17)
178 {
179 offset = rx_msg->len - 15;
180 memset (backend->midi_info.company, 0, BE_COMPANY_LEN);
181 memcpy (backend->midi_info.company, &rx_msg->data[5],
182 rx_msg->len == 15 ? 1 : BE_COMPANY_LEN);
183 memcpy (backend->midi_info.family, &rx_msg->data[6 + offset],
184 BE_FAMILY_LEN);
185 memcpy (backend->midi_info.model, &rx_msg->data[8 + offset],
186 BE_MODEL_LEN);
187 memcpy (backend->midi_info.version, &rx_msg->data[10 + offset],
188 BE_VERSION_LEN);
189
190 snprintf (backend->device_name, LABEL_MAX,
191 "%02x-%02x-%02x %02x-%02x %02x-%02x %d.%d.%d.%d",
192 backend->midi_info.company[0],
193 backend->midi_info.company[1],
194 backend->midi_info.company[2],
195 backend->midi_info.family[0],
196 backend->midi_info.family[1],
197 backend->midi_info.model[0],
198 backend->midi_info.model[1],
199 backend->midi_info.version[0],
200 backend->midi_info.version[1],
201 backend->midi_info.version[2],
202 backend->midi_info.version[3]);
203 snprintf (backend->device_desc.name, LABEL_MAX, "%s",
204 backend->device_name);
205 debug_print (1, "Detected device: %s\n", backend->device_name);
206 }
207 else
208 {
209 debug_print (1, "Illegal MIDI identity reply length\n");
210 }
211 }
212 else
213 {
214 debug_print (1, "Illegal SUB-ID2\n");
215 }
216
217 free_msg (rx_msg);
218 }
219
220 gint
221 backend_init (struct backend *backend, const gchar * id)
222 {
223 snd_rawmidi_params_t *params;
224 gint err;
225
226 backend->inputp = NULL;
227 backend->outputp = NULL;
228 backend->pfds = NULL;
229 backend->rx_len = 0;
230 backend->cache = NULL;
231 backend->buffer = NULL;
232
233 if (!strcmp (id, BE_SYSTEM_ID))
234 {
235 backend->type = BE_TYPE_SYSTEM;
236 return 0;
237 }
238
239 backend->type = BE_TYPE_MIDI;
240 backend->buffer = g_malloc (sizeof (guint8) * BE_INT_BUF_LEN);
241
242 debug_print (1, "Initializing backend to '%s'...\n", id);
243
244 if ((err =
245 snd_rawmidi_open (&backend->inputp, &backend->outputp,
246 id, SND_RAWMIDI_NONBLOCK | SND_RAWMIDI_SYNC)) < 0)
247 {
248 error_print ("Error while opening MIDI port: %s\n", g_strerror (-err));
249 goto cleanup;
250 }
251
252 debug_print (1, "Setting blocking mode...\n");
253 if ((err = snd_rawmidi_nonblock (backend->outputp, 0)) < 0)
254 {
255 error_print ("Error while setting blocking mode\n");
256 goto cleanup;
257 }
258 if ((err = snd_rawmidi_nonblock (backend->inputp, 1)) < 0)
259 {
260 error_print ("Error while setting blocking mode\n");
261 goto cleanup;
262 }
263
264 debug_print (1, "Stopping device...\n");
265 if (snd_rawmidi_write (backend->outputp, "\xfc", 1) < 0)
266 {
267 error_print ("Error while stopping device\n");
268 }
269
270 backend->npfds = snd_rawmidi_poll_descriptors_count (backend->inputp);
271 backend->pfds = malloc (backend->npfds * sizeof (struct pollfd));
272
273 snd_rawmidi_poll_descriptors (backend->inputp, backend->pfds,
274 backend->npfds);
275 err = snd_rawmidi_params_malloc (&params);
276 if (err)
277 {
278 goto cleanup;
279 }
280
281 err = snd_rawmidi_params_current (backend->inputp, params);
282 if (err)
283 {
284 goto cleanup_params;
285 }
286
287 err =
288 snd_rawmidi_params_set_buffer_size (backend->inputp, params,
289 BE_DEV_RING_BUF_LEN);
290 if (err)
291 {
292 goto cleanup_params;
293 }
294
295 err = snd_rawmidi_params (backend->inputp, params);
296 if (err)
297 {
298 goto cleanup_params;
299 }
300
301 backend_midi_handshake (backend);
302
303 return 0;
304
305 cleanup_params:
306 snd_rawmidi_params_free (params);
307 cleanup:
308 backend_destroy (backend);
309 g_free (backend->buffer);
310 return err;
311 }
312
313 ssize_t
314 backend_tx_raw (struct backend *backend, const guint8 * data, guint len)
315 {
316 ssize_t tx_len;
317
318 if (!backend->outputp)
319 {
320 error_print ("Output port is NULL\n");
321 return -ENOTCONN;
322 }
323
324 snd_rawmidi_read (backend->inputp, NULL, 0); // trigger reading
325
326 tx_len = snd_rawmidi_write (backend->outputp, data, len);
327 if (tx_len < 0)
328 {
329 error_print ("Error while writing to device: %s\n",
330 snd_strerror (tx_len));
331 }
332 return tx_len;
333 }
334
335 static gint
336 backend_tx_sysex_with_state_update (struct backend *backend,
337 struct sysex_transfer *transfer,
338 gboolean update)
339 {
340 ssize_t tx_len;
341 guint total;
342 guint len;
343 guchar *b;
344
345 if (update)
346 {
347 transfer->err = 0;
348 transfer->active = TRUE;
349 transfer->status = SENDING;
350 }
351
352 b = transfer->raw->data;
353 total = 0;
354 while (total < transfer->raw->len && transfer->active)
355 {
356 len = transfer->raw->len - total;
357 if (len > BE_MAX_TX_LEN)
358 {
359 len = BE_MAX_TX_LEN;
360 }
361
362 tx_len = backend_tx_raw (backend, b, len);
363 if (tx_len < 0)
364 {
365 transfer->err = tx_len;
366 break;
367 }
368 b += len;
369 total += len;
370 }
371
372 if (!transfer->active)
373 {
374 transfer->err = -ECANCELED;
375 }
376
377 if (!transfer->err && debug_level >= 2)
378 {
379 gchar *text = debug_get_hex_data (debug_level, transfer->raw->data,
380 transfer->raw->len);
381 debug_print (2, "Raw message sent (%d): %s\n", transfer->raw->len,
382 text);
383 free (text);
384 }
385
386 if (update)
387 {
388 transfer->active = FALSE;
389 transfer->status = FINISHED;
390 }
391 return transfer->err;
392 }
393
394 gint
395 backend_tx_sysex_no_update (struct backend *backend,
396 struct sysex_transfer *transfer)
397 {
398 return backend_tx_sysex_with_state_update (backend, transfer, FALSE);
399 }
400
401 gint
402 backend_tx_sysex (struct backend *backend, struct sysex_transfer *transfer)
403 {
404 return backend_tx_sysex_with_state_update (backend, transfer, TRUE);
405 }
406
407 //Access to this function must be synchronized.
408
409 void
410 backend_rx_drain (struct backend *backend)
411 {
412 struct sysex_transfer transfer;
413 transfer.timeout = 1000;
414 transfer.batch = FALSE;
415
416 debug_print (2, "Draining buffers...\n");
417 backend->rx_len = 0;
418 snd_rawmidi_drain (backend->inputp);
419 while (!backend_rx_sysex (backend, &transfer))
420 {
421 free_msg (transfer.raw);
422 }
423 }
424
425 static inline gboolean
426 backend_is_byte_rt_msg (guint8 b)
427 {
428 return (b >= 0xf1 && b <= 0xf6) || (b >= 0xf8 && b <= 0xff);
429 }
430
431 static ssize_t
432 backend_rx_raw (struct backend *backend, struct sysex_transfer *transfer)
433 {
434 ssize_t rx_len, rx_len_msg;
435 unsigned short revents;
436 gint err;
437 gchar *text;
438 guint8 tmp[BE_TMP_BUFF_LEN];
439 guint8 *tmp_msg, *data = backend->buffer + backend->rx_len;
440
441 if (!backend->inputp)
442 {
443 error_print ("Input port is NULL\n");
444 return -ENOTCONN;
445 }
446
447 while (1)
448 {
449 if (!transfer->active)
450 {
451 return -ECANCELED;
452 }
453
454 debug_print (4, "Checking timeout (%d ms, %d ms, %s mode)...\n",
455 transfer->time, transfer->timeout,
456 transfer->batch ? "batch" : "single");
457 if (((transfer->batch && transfer->status == RECEIVING)
458 || !transfer->batch) && transfer->timeout > -1
459 && transfer->time >= transfer->timeout)
460 {
461 debug_print (1, "Timeout\n");
462 return -ETIMEDOUT;
463 }
464
465 debug_print (4, "Polling...\n");
466 err = poll (backend->pfds, backend->npfds, BE_POLL_TIMEOUT_MS);
467
468 if (err == 0)
469 {
470 if ((transfer->batch && transfer->status == RECEIVING)
471 || !transfer->batch)
472 {
473 transfer->time += BE_POLL_TIMEOUT_MS;
474 }
475 continue;
476 }
477
478 if (err < 0)
479 {
480 error_print ("Error while polling. %s.\n", g_strerror (errno));
481 if (errno == EINTR)
482 {
483 return -ECANCELED;
484 }
485 return err;
486 }
487
488 if ((err = snd_rawmidi_poll_descriptors_revents (backend->inputp,
489 backend->pfds,
490 backend->npfds,
491 &revents)) < 0)
492 {
493 error_print ("Error while getting poll events. %s.\n",
494 snd_strerror (err));
495 return err;
496 }
497
498 if (revents & (POLLERR | POLLHUP))
499 {
500 return -ENODATA;
501 }
502
503 if (!(revents & POLLIN))
504 {
505 continue;
506 }
507
508 debug_print (4, "Reading data...\n");
509 rx_len = snd_rawmidi_read (backend->inputp, tmp, BE_TMP_BUFF_LEN);
510
511 if (rx_len == -EAGAIN || rx_len == 0)
512 {
513 continue;
514 }
515
516 //Everything is skipped until a 0xf0 is found. This includes every RT MIDI message.
517 tmp_msg = tmp;
518 if (!backend->rx_len && tmp[0] != 0xf0)
519 {
520 if (debug_level >= 4)
521 {
522 gchar *text = debug_get_hex_data (debug_level, tmp, rx_len);
523 debug_print (4, "Skipping partial message (%zd): %s\n",
524 rx_len, text);
525 free (text);
526 }
527
528 tmp_msg++;
529 rx_len_msg = 1;
530 for (gint i = 1; i < rx_len; i++, tmp_msg++, rx_len_msg++)
531 {
532 if (*tmp_msg == 0xf0)
533 {
534 break;
535 }
536 }
537 rx_len -= rx_len_msg;
538 }
539
540 if (rx_len == 0)
541 {
542 transfer->time += BE_POLL_TIMEOUT_MS;
543 continue;
544 }
545
546 if (rx_len > 0)
547 {
548 memcpy (backend->buffer + backend->rx_len, tmp_msg, rx_len);
549 backend->rx_len += rx_len;
550 break;
551 }
552
553 if (rx_len < 0)
554 {
555 error_print ("Error while reading from device: %s\n",
556 snd_strerror (rx_len));
557 break;
558 }
559 }
560
561 if (debug_level >= 3)
562 {
563 text = debug_get_hex_data (debug_level, data, rx_len);
564 debug_print (3, "Queued data (%zu): %s\n", rx_len, text);
565 free (text);
566 }
567
568 return rx_len;
569 }
570
571 //Access to this function must be synchronized.
572
573 gint
574 backend_rx_sysex (struct backend *backend, struct sysex_transfer *transfer)
575 {
576 gint next_check, len, i;
577 guint8 *b;
578 ssize_t rx_len;
579
580 transfer->err = 0;
581 transfer->time = 0;
582 transfer->active = TRUE;
583 transfer->status = WAITING;
584 transfer->raw = g_byte_array_sized_new (BE_INT_BUF_LEN);
585
586 next_check = 0;
587 while (1)
588 {
589 if (backend->rx_len == next_check)
590 {
591 debug_print (4, "Reading from MIDI device...\n");
592 if (transfer->batch)
593 {
594 transfer->time = 0;
595 }
596 rx_len = backend_rx_raw (backend, transfer);
597
598 if (rx_len == -ENODATA || rx_len == -ETIMEDOUT
599 || rx_len == -ECANCELED)
600 {
601 if (transfer->batch)
602 {
603 break;
604 }
605 else
606 {
607 transfer->err = rx_len;
608 goto end;
609 }
610 }
611 else if (rx_len < 0)
612 {
613 transfer->err = -EIO;
614 goto end;
615 }
616 }
617 else
618 {
619 debug_print (4, "Reading from internal buffer...\n");
620 }
621
622 transfer->status = RECEIVING;
623 len = -1;
624 b = backend->buffer + next_check;
625 for (; next_check < backend->rx_len; next_check++, b++)
626 {
627 if (*b == 0xf7)
628 {
629 next_check++;
630 len = next_check;
631 break;
632 }
633 }
634
635 //We filter out whatever SysEx message not suitable for Elektroid.
636
637 if (len > 0)
638 {
639 debug_print (3, "Copying %d bytes...\n", len);
640
641 //Filter out RT messages
642 b = backend->buffer;
643 for (i = 0; i < len; i++, b++)
644 {
645 if (!backend_is_byte_rt_msg (*b))
646 {
647 g_byte_array_append (transfer->raw, b, 1);
648 }
649 }
650
651 backend->rx_len -= len;
652 memmove (backend->buffer, backend->buffer + next_check,
653 backend->rx_len);
654 transfer->err = 0;
655 next_check = 0;
656
657 //Filter empty message
658 if (transfer->raw->len == 2
659 && !memcmp (transfer->raw->data, "\xf0\xf7", 2))
660 {
661 debug_print (4, "Removing empty message...\n");
662 g_byte_array_remove_range (transfer->raw, 0, 2);
663 continue;
664 }
665
666 if (debug_level >= 4)
667 {
668 gchar *text =
669 debug_get_hex_data (debug_level, transfer->raw->data,
670 transfer->raw->len);
671 debug_print (4, "Queued data (%d): %s\n",
672 transfer->raw->len, text);
673 free (text);
674 }
675 }
676 else
677 {
678 debug_print (4, "No message in the queue. Continuing...\n");
679 }
680
681 if (transfer->raw->len && !transfer->batch)
682 {
683 break;
684 }
685 }
686
687 end:
688 if (!transfer->raw->len)
689 {
690 transfer->err = -ETIMEDOUT;
691 }
692 if (transfer->err)
693 {
694 free_msg (transfer->raw);
695 transfer->raw = NULL;
696 }
697 else
698 {
699 if (debug_level >= 2)
700 {
701 gchar *text = debug_get_hex_data (debug_level, transfer->raw->data,
702 transfer->raw->len);
703 debug_print (2, "Raw message received (%d): %s\n",
704 transfer->raw->len, text);
705 free (text);
706 }
707
708 }
709 transfer->active = FALSE;
710 transfer->status = FINISHED;
711 return transfer->err;
712 }
713
714 //Synchronized
715
716 gint
717 backend_tx (struct backend *backend, GByteArray * tx_msg)
718 {
719 struct sysex_transfer transfer;
720 transfer.raw = tx_msg;
721 g_mutex_lock (&backend->mutex);
722 backend_tx_sysex (backend, &transfer);
723 g_mutex_unlock (&backend->mutex);
724 free_msg (tx_msg);
725 return transfer.err;
726 }
727
728 //Not synchronized. Only meant to be called from backend_tx_and_rx_sysex_transfer.
729
730 static gint
731 backend_tx_and_rx_sysex_transfer_no_cache (struct backend *backend,
732 struct sysex_transfer *transfer,
733 gboolean free)
734 {
735 transfer->batch = FALSE;
736
737 backend_tx_sysex (backend, transfer);
738 if (free)
739 {
740 free_msg (transfer->raw);
741 transfer->raw = NULL;
742 }
743 if (!transfer->err)
744 {
745 backend_rx_sysex (backend, transfer);
746 }
747
748 return transfer->err;
749 }
750
751 //Synchronized
752
753 gint
754 backend_tx_and_rx_sysex_transfer (struct backend *backend,
755 struct sysex_transfer *transfer,
756 gboolean free)
757 {
758 GBytes *key;
759 GByteArray *rx_msg;
760 transfer->batch = FALSE;
761
762 g_mutex_lock (&backend->mutex);
763 if (backend->cache)
764 {
765 key = g_bytes_new (transfer->raw->data, transfer->raw->len);
766 rx_msg = g_hash_table_lookup (backend->cache, key);
767 if (rx_msg)
768 {
769 transfer->raw = g_byte_array_sized_new (rx_msg->len);
770 g_byte_array_append (transfer->raw, rx_msg->data, rx_msg->len);
771 transfer->err = 0;
772 g_bytes_unref (key);
773 goto end;
774 }
775
776 if (backend_tx_and_rx_sysex_transfer_no_cache (backend, transfer, free))
777 {
778 g_bytes_unref (key);
779 goto end;
780 }
781
782 rx_msg = g_byte_array_sized_new (transfer->raw->len);
783 g_byte_array_append (rx_msg, transfer->raw->data, transfer->raw->len);
784 g_hash_table_insert (backend->cache, key, rx_msg);
785 }
786 else
787 {
788 backend_tx_and_rx_sysex_transfer_no_cache (backend, transfer, free);
789 }
790
791 end:
792 g_mutex_unlock (&backend->mutex);
793 return transfer->err;
794 }
795
796 //Synchronized
797 //A timeout of 0 means infinity; a negative timeout means the default timeout.
798
799 GByteArray *
800 backend_tx_and_rx_sysex (struct backend *backend,
801 GByteArray * tx_msg, gint timeout)
802 {
803 struct sysex_transfer transfer;
804 transfer.raw = tx_msg;
805 transfer.timeout = timeout < 0 ? BE_SYSEX_TIMEOUT_MS : timeout;
806 backend_tx_and_rx_sysex_transfer (backend, &transfer, TRUE);
807 return transfer.raw;
808 }
809
810 gboolean
811 backend_check (struct backend *backend)
812 {
813 return backend->type == BE_TYPE_SYSTEM || (backend->type == BE_TYPE_MIDI
814 && backend->inputp
815 && backend->outputp);
816 }
817
818 static void
819 backend_get_system_subdevices (snd_ctl_t * ctl, int card, int device,
820 GArray * devices)
821 {
822 snd_rawmidi_info_t *info;
823 const gchar *name;
824 const gchar *sub_name;
825 int subs, subs_in, subs_out;
826 int sub;
827 int err;
828 struct backend_system_device *backend_system_device;
829
830 snd_rawmidi_info_alloca (&info);
831 snd_rawmidi_info_set_device (info, device);
832 snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_INPUT);
833 err = snd_ctl_rawmidi_info (ctl, info);
834 if (err >= 0)
835 {
836 subs_in = snd_rawmidi_info_get_subdevices_count (info);
837 }
838 else
839 {
840 subs_in = 0;
841 }
842
843 snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_OUTPUT);
844 err = snd_ctl_rawmidi_info (ctl, info);
845 if (err >= 0)
846 {
847 subs_out = snd_rawmidi_info_get_subdevices_count (info);
848 }
849 else
850 {
851 subs_out = 0;
852 }
853
854 subs = subs_in > subs_out ? subs_in : subs_out;
855 if (!subs)
856 {
857 return;
858 }
859
860 if (subs_in <= 0 || subs_out <= 0)
861 {
862 return;
863 }
864
865 for (sub = 0; sub < subs; sub++)
866 {
867 snd_rawmidi_info_set_subdevice (info, sub);
868
869 snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_INPUT);
870 err = snd_ctl_rawmidi_info (ctl, info);
871 if (err < 0)
872 {
873 debug_print (1,
874 "Cannot get rawmidi input information %d:%d:%d: %s\n",
875 card, device, sub, snd_strerror (err));
876 continue;
877 }
878
879 snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_OUTPUT);
880 err = snd_ctl_rawmidi_info (ctl, info);
881 if (err < 0)
882 {
883 debug_print (1,
884 "Cannot get rawmidi output information %d:%d:%d: %s\n",
885 card, device, sub, snd_strerror (err));
886 continue;
887 }
888
889 name = snd_rawmidi_info_get_name (info);
890 sub_name = snd_rawmidi_info_get_subdevice_name (info);
891
892 debug_print (1, "Adding hw:%d (name '%s', subname '%s')...\n", card,
893 name, sub_name);
894 backend_system_device = malloc (sizeof (struct backend_system_device));
895 snprintf (backend_system_device->id, LABEL_MAX, BE_DEVICE_NAME, card,
896 device, sub);
897 snprintf (backend_system_device->name, LABEL_MAX,
898 BE_DEVICE_NAME ": %s%s%s", card, device, sub, name,
899 strlen (sub_name) ? ", " : "", sub_name);
900
901 g_array_append_vals (devices, backend_system_device, 1);
902 }
903 }
904
905 static void
906 backend_fill_card_devices (gint card, GArray * devices)
907 {
908 snd_ctl_t *ctl;
909 gchar name[32];
910 gint device;
911 gint err;
912
913 sprintf (name, "hw:%d", card);
914 if ((err = snd_ctl_open (&ctl, name, 0)) < 0)
915 {
916 error_print ("Cannot open control for card %d: %s\n",
917 card, snd_strerror (err));
918 return;
919 }
920 device = -1;
921 while (!(err = snd_ctl_rawmidi_next_device (ctl, &device)) && device >= 0)
922 {
923 backend_get_system_subdevices (ctl, card, device, devices);
924 }
925 if (err < 0)
926 {
927 error_print ("Cannot determine device number: %s\n",
928 snd_strerror (err));
929 }
930 snd_ctl_close (ctl);
931 }
932
933 GArray *
934 backend_get_system_devices ()
935 {
936 gint card, err;
937 GArray *devices =
938 g_array_new (FALSE, FALSE, sizeof (struct backend_system_device));
939
940 card = -1;
941 while (!(err = snd_card_next (&card)) && card >= 0)
942 {
943 backend_fill_card_devices (card, devices);
944 }
945 if (err < 0)
946 {
947 error_print ("Cannot determine card number: %s\n", snd_strerror (err));
948 }
949
950 return devices;
951 }
952
953 gchar *
954 backend_get_fs_ext (const struct device_desc *desc,
955 const struct fs_operations *ops)
956 {
957 gchar *ext = malloc (LABEL_MAX);
958 snprintf (ext, LABEL_MAX, "%s", ops->type_ext);
959 return ext;
960 }
961
962 void
963 backend_destroy_data (struct backend *backend)
964 {
965 debug_print (1, "Destroying backend data...\n");
966 g_free (backend->data);
967 backend->data = NULL;
968 }
969
970 gint
971 backend_program_change (struct backend *backend, guint8 channel,
972 guint8 program)
973 {
974 ssize_t size;
975 guint8 msg[2];
976
977 msg[0] = 0xc0 | (channel & 0xf);
978 msg[1] = program & 0x7f;
979
980 if ((size = backend_tx_raw (backend, (guint8 *) msg, 2)) < 0)
981 {
982 return size;
983 }
984 return 0;
985 }
0 /*
1 * backend.h
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <alsa/asoundlib.h>
21 #include "utils.h"
22
23 #ifndef BACKEND_H
24 #define BACKEND_H
25
26 #define BE_FILE_ICON_WAVE "elektroid-wave-symbolic"
27 #define BE_FILE_ICON_SEQ "elektroid-sequence-symbolic"
28 #define BE_FILE_ICON_PRJ "elektroid-project-symbolic"
29 #define BE_FILE_ICON_SND "elektroid-sound-symbolic"
30
31 #define BE_DUMP_TIMEOUT 5000 //With and E-Mu ESI-2000 it takes this more than 3 seconds to receive to receive some packets after the process has started.
32 #define BE_REST_TIME_US 50000
33 #define BE_SYSEX_TIMEOUT_MS 5000
34 #define BE_SYSEX_TIMEOUT_GUESS_MS 500 //When the request is not implemented, 5 s is too much.
35 #define BE_SAMPLE_ID_NAME_SEPARATOR ":"
36
37 #define BE_COMPANY_LEN 3
38 #define BE_FAMILY_LEN 2
39 #define BE_MODEL_LEN 2
40 #define BE_VERSION_LEN 4
41
42 #define BE_SYSTEM_ID "SYSTEM_ID"
43
44 struct backend_storage_stats
45 {
46 const gchar *name;
47 guint64 bsize;
48 guint64 bfree;
49 };
50
51 typedef void (*t_destroy_data) (struct backend *);
52
53 typedef gint (*t_get_storage_stats) (struct backend *, gint,
54 struct backend_storage_stats *);
55
56 struct backend_midi_info
57 {
58 gchar company[BE_COMPANY_LEN];
59 gchar family[BE_FAMILY_LEN];
60 gchar model[BE_MODEL_LEN];
61 gchar version[BE_VERSION_LEN];
62 };
63
64 enum backend_type
65 {
66 BE_TYPE_NONE,
67 BE_TYPE_SYSTEM,
68 BE_TYPE_MIDI
69 };
70
71 struct backend
72 {
73 enum backend_type type;
74 struct device_desc device_desc;
75 struct backend_midi_info midi_info;
76 snd_rawmidi_t *inputp;
77 snd_rawmidi_t *outputp;
78 GMutex mutex;
79 //Internal buffer
80 guint8 *buffer;
81 ssize_t rx_len;
82 //Linux
83 gint npfds;
84 struct pollfd *pfds;
85 gchar device_name[LABEL_MAX];
86 //Message cache
87 GHashTable *cache;
88 //These must be filled by the concrete backend.
89 const struct fs_operations **fs_ops;
90 t_destroy_data destroy_data;
91 t_sysex_transfer upgrade_os;
92 t_get_storage_stats get_storage_stats;
93 void *data;
94 };
95
96 struct backend_system_device
97 {
98 gchar name[LABEL_MAX];
99 gchar id[LABEL_MAX];
100 };
101
102 gint backend_init (struct backend *, const gchar *);
103
104 void backend_destroy (struct backend *);
105
106 ssize_t backend_tx_raw (struct backend *, const guint8 *, guint);
107
108 gint backend_tx_sysex_no_update (struct backend *, struct sysex_transfer *);
109
110 gint backend_tx_sysex (struct backend *, struct sysex_transfer *);
111
112 gint backend_rx_sysex (struct backend *, struct sysex_transfer *);
113
114 gint backend_tx (struct backend *, GByteArray *);
115
116 gint backend_tx_and_rx_sysex_transfer (struct backend *,
117 struct sysex_transfer *, gboolean);
118
119 GByteArray *backend_tx_and_rx_sysex (struct backend *, GByteArray *, gint);
120
121 void backend_rx_drain (struct backend *);
122
123 gboolean backend_check (struct backend *);
124
125 void backend_enable_cache (struct backend *);
126
127 void backend_disable_cache (struct backend *);
128
129 GArray *backend_get_system_devices ();
130
131 const struct fs_operations *backend_get_fs_operations (struct backend *, gint,
132 const char *);
133
134 const gchar *backend_get_fs_name (struct backend *, guint);
135
136 gchar *backend_get_fs_ext (const struct device_desc *,
137 const struct fs_operations *);
138
139 gdouble backend_get_storage_stats_percent (struct backend_storage_stats *);
140
141 void backend_destroy_data (struct backend *);
142
143 gint backend_program_change (struct backend *, guint8, guint8);
144
145 #endif
1818 */
1919
2020 #include "browser.h"
21 #include "backend.h"
22
23 static void
24 browser_widget_set_sensitive (gpointer widget, gpointer data)
25 {
26 gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
27 }
28
29 static void
30 browser_widget_set_insensitive (gpointer widget, gpointer data)
31 {
32 gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE);
33 }
2134
2235 gint
23 browser_sort_samples (GtkTreeModel * model,
36 browser_sort_by_name (GtkTreeModel * model,
2437 GtkTreeIter * a, GtkTreeIter * b, gpointer data)
2538 {
26 struct item *itema;
27 struct item *itemb;
39 struct item itema;
40 struct item itemb;
2841 gint ret = 0;
2942
30 itema = browser_get_item (model, a);
31 itemb = browser_get_item (model, b);
32
33 if (itema->type == itemb->type)
34 {
35 ret = g_utf8_collate (itema->name, itemb->name);
43 browser_set_item (model, a, &itema);
44 browser_set_item (model, b, &itemb);
45
46 if (itema.type == itemb.type)
47 {
48 ret = g_utf8_collate (itema.name, itemb.name);
3649 }
3750 else
3851 {
39 ret = itema->type > itemb->type;
40 }
41
42 browser_free_item (itema);
43 browser_free_item (itemb);
52 ret = itema.type > itemb.type;
53 }
4454
4555 return ret;
4656 }
4757
4858 gint
49 browser_sort_data (GtkTreeModel * model,
50 GtkTreeIter * a, GtkTreeIter * b, gpointer data)
51 {
52 struct item *itema;
53 struct item *itemb;
59 browser_sort_by_id (GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b,
60 gpointer data)
61 {
62 struct item itema;
63 struct item itemb;
5464 gint ret = 0;
5565
56 itema = browser_get_item (model, a);
57 itemb = browser_get_item (model, b);
58
59 ret = itema->index > itemb->index;
60
61 browser_free_item (itema);
62 browser_free_item (itemb);
66 browser_set_item (model, a, &itema);
67 browser_set_item (model, b, &itemb);
68
69 if (itema.type == itemb.type)
70 {
71 ret = itema.id > itemb.id;
72 }
73 else
74 {
75 ret = itema.type > itemb.type;
76 }
6377
6478 return ret;
6579 }
6680
67 struct item *
68 browser_get_item (GtkTreeModel * model, GtkTreeIter * iter)
69 {
70 struct item *item = malloc (sizeof (struct item));
71
81 void
82 browser_set_item (GtkTreeModel * model, GtkTreeIter * iter, struct item *item)
83 {
84 gchar *name;
7285 gtk_tree_model_get (model, iter, BROWSER_LIST_STORE_TYPE_FIELD, &item->type,
73 BROWSER_LIST_STORE_NAME_FIELD, &item->name,
86 BROWSER_LIST_STORE_NAME_FIELD, &name,
7487 BROWSER_LIST_STORE_SIZE_FIELD, &item->size,
75 BROWSER_LIST_STORE_INDEX_FIELD, &item->index, -1);
76
77 return item;
88 BROWSER_LIST_STORE_ID_FIELD, &item->id, -1);
89 snprintf (item->name, LABEL_MAX, "%s", name);
90 g_free (name);
7891 }
7992
8093 void
119132 void
120133 browser_go_up (GtkWidget * object, gpointer data)
121134 {
122 char *dup;
123 char *new_path;
124 struct browser *browser = data;
125
126 if (strcmp (browser->dir, "/") != 0)
127 {
128 dup = strdup (browser->dir);
129 new_path = dirname (dup);
130 strcpy (browser->dir, new_path);
131 free (dup);
132 if (browser->notify_dir_change)
135 struct browser *browser = data;
136
137 g_mutex_lock (&browser->mutex);
138 if (!browser->loading)
139 {
140 if (strcmp (browser->dir, "/"))
133141 {
134 browser->notify_dir_change (browser);
142 gchar *dup = strdup (browser->dir);
143 gchar *new_path = dirname (dup);
144 strcpy (browser->dir, new_path);
145 free (dup);
135146 }
136147 }
148 g_mutex_unlock (&browser->mutex);
137149
138150 g_idle_add (browser_load_dir, browser);
139151 }
143155 GtkTreeViewColumn * column, gpointer data)
144156 {
145157 GtkTreeIter iter;
146 struct item *item;
158 struct item item;
147159 struct browser *browser = data;
148160 GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model
149161 (browser->view));
150162
151163 gtk_tree_model_get_iter (model, &iter, path);
152 item = browser_get_item (model, &iter);
153
154 if (item->type == ELEKTROID_DIR)
155 {
156 if (strcmp (browser->dir, "/") != 0)
164 browser_set_item (model, &iter, &item);
165
166 if (item.type == ELEKTROID_DIR)
167 {
168 if (strcmp (browser->dir, "/"))
157169 {
158170 strcat (browser->dir, "/");
159171 }
160 strcat (browser->dir, item->name);
172 strcat (browser->dir, item.name);
161173 browser_load_dir (browser);
162 if (browser->notify_dir_change)
163 {
164 browser->notify_dir_change (browser);
165 }
166 }
167
168 browser_free_item (item);
174 }
169175 }
170176
171177 gint
176182 return gtk_tree_selection_count_selected_rows (selection);
177183 }
178184
179 void
180 browser_free_item (struct item *item)
181 {
182 g_free (item->name);
183 g_free (item);
184 }
185
186185 gchar *
187186 browser_get_item_path (struct browser *browser, struct item *item)
188187 {
189188 gchar *path = chain_path (browser->dir, item->name);
190189 debug_print (1, "Using %s path for item %s (%d)...\n", path, item->name,
191 item->index);
190 item->id);
192191 return path;
193192 }
194193
195194 gchar *
196195 browser_get_item_id_path (struct browser *browser, struct item *item)
197196 {
198 gchar *id = browser->fs_ops->getid (item);
199 gchar *path = chain_path (browser->dir, id);
200 debug_print (1, "Using %s path for item %s (%d)...\n", path, item->name,
201 item->index);
202 g_free (id);
197 gchar *filename = get_filename (browser->fs_ops->options, item);
198 gchar *path = chain_path (browser->dir, filename);
199 debug_print (1, "Using %s path for item %s (id %d)...\n", path, item->name,
200 item->id);
201 g_free (filename);
203202 return path;
204203 }
205204
206205 static void
207 local_add_dentry_item (struct browser *browser, struct item_iterator *iter)
208 {
209 gchar *hsize;
206 browser_add_dentry_item (struct browser *browser, struct item_iterator *iter)
207 {
208 gchar *hsize, *slot;
210209 GtkListStore *list_store =
211210 GTK_LIST_STORE (gtk_tree_view_get_model (browser->view));
212211
213212 hsize = iter->item.size ? get_human_size (iter->item.size, TRUE) : "";
213 slot = (browser->fs_ops->options & FS_OPTION_SLOT_STORAGE)
214 && browser->fs_ops->get_slot ? browser->fs_ops->get_slot (&iter->item,
215 browser->backend)
216 : "";
214217
215218 gtk_list_store_insert_with_values (list_store, NULL, -1,
216219 BROWSER_LIST_STORE_ICON_FIELD,
225228 hsize,
226229 BROWSER_LIST_STORE_TYPE_FIELD,
227230 iter->item.type,
228 BROWSER_LIST_STORE_INDEX_FIELD,
229 iter->item.index, -1);
231 BROWSER_LIST_STORE_ID_FIELD,
232 iter->item.id,
233 BROWSER_LIST_STORE_SLOT_FIELD, slot, -1);
230234 if (strlen (hsize))
231235 {
232236 g_free (hsize);
233237 }
238
239 if (strlen (slot))
240 {
241 g_free (slot);
242 }
234243 }
235244
236245 static gboolean
237 browser_file_match_extensions (struct browser *browser,
238 struct item_iterator *iter)
239 {
240 gboolean match;
241 const gchar *entry_ext;
242 gchar **ext = browser->extensions;
243
244 if (iter->item.type == ELEKTROID_DIR)
245 {
246 return TRUE;
247 }
248
249 if (!ext)
250 {
251 return TRUE;
252 }
253
254 entry_ext = get_ext (iter->item.name);
255
256 if (!entry_ext)
257 {
258 return FALSE;
259 }
260
261 match = FALSE;
262 while (*ext != NULL && !match)
263 {
264 match = !strcasecmp (entry_ext, *ext);
265 ext++;
266 }
267
268 return match;
246 browser_load_dir_runner_hide_spinner (gpointer data)
247 {
248 struct browser *browser = data;
249 g_slist_foreach (browser->sensitive_widgets, browser_widget_set_sensitive,
250 NULL);
251 gtk_spinner_stop (GTK_SPINNER (browser->spinner));
252 gtk_stack_set_visible_child_name (GTK_STACK (browser->stack), "list");
253 return FALSE;
254 }
255
256 static gboolean
257 browser_load_dir_runner_show_spinner (gpointer data)
258 {
259 struct browser *browser = data;
260 g_slist_foreach (browser->sensitive_widgets, browser_widget_set_insensitive,
261 NULL);
262 gtk_stack_set_visible_child_name (GTK_STACK (browser->stack), "spinner");
263 gtk_spinner_start (GTK_SPINNER (browser->spinner));
264 return FALSE;
265 }
266
267 static gboolean
268 browser_load_dir_runner_update_ui (gpointer data)
269 {
270 struct browser *browser = data;
271 gboolean active = !browser->backend
272 || browser->backend->type == BE_TYPE_SYSTEM;
273
274 notifier_set_active (browser->notifier, active);
275
276 if (browser->iter)
277 {
278 while (!next_item_iterator (browser->iter))
279 {
280 if (iter_matches_extensions (browser->iter, browser->extensions))
281 {
282 browser_add_dentry_item (browser, browser->iter);
283 }
284 }
285 free_item_iterator (browser->iter);
286 g_free (browser->iter);
287 browser->iter = NULL;
288 }
289
290 g_thread_join (browser->thread);
291 browser->thread = NULL;
292
293 if (browser->check_callback)
294 {
295 browser->check_callback ();
296 }
297 gtk_tree_view_columns_autosize (browser->view);
298
299 g_mutex_lock (&browser->mutex);
300 browser->loading = FALSE;
301 g_mutex_unlock (&browser->mutex);
302
303 return FALSE;
304 }
305
306 static gpointer
307 browser_load_dir_runner (gpointer data)
308 {
309 gint err;
310 struct browser *browser = data;
311
312 g_idle_add (browser_load_dir_runner_show_spinner, browser);
313 browser->iter = g_malloc (sizeof (struct item_iterator));
314 err = browser->fs_ops->readdir (browser->backend, browser->iter,
315 browser->dir);
316 g_idle_add (browser_load_dir_runner_hide_spinner, browser);
317 if (err)
318 {
319 error_print ("Error while opening '%s' dir\n", browser->dir);
320 g_free (browser->iter);
321 browser->iter = NULL;
322 }
323 g_idle_add (browser_load_dir_runner_update_ui, browser);
324 return NULL;
269325 }
270326
271327 gboolean
272328 browser_load_dir (gpointer data)
273329 {
274 struct item_iterator iter;
275 struct browser *browser = data;
330 struct browser *browser = data;
331
332 g_mutex_lock (&browser->mutex);
333 if (browser->loading)
334 {
335 debug_print (1, "Browser already loading. Skipping load...\n");
336 g_mutex_unlock (&browser->mutex);
337 return FALSE;
338 }
339 else
340 {
341 browser->loading = TRUE;
342 }
343 g_mutex_unlock (&browser->mutex);
276344
277345 browser_reset (browser);
278346
279 if (browser->fs_ops->readdir (&iter, browser->dir, browser->data))
280 {
281 error_print ("Error while opening %s dir\n", browser->dir);
282 goto end;
283 }
284
285 while (!next_item_iterator (&iter))
286 {
287 if (browser_file_match_extensions (browser, &iter))
288 {
289 local_add_dentry_item (browser, &iter);
290 }
291 }
292 free_item_iterator (&iter);
293
294 end:
295 if (browser->check_callback)
296 {
297 browser->check_callback ();
298 }
299 gtk_tree_view_columns_autosize (browser->view);
347 if (!browser->fs_ops || !browser->fs_ops->readdir)
348 {
349 return FALSE;
350 }
351
352 browser->thread = g_thread_new ("browser_thread", browser_load_dir_runner,
353 browser);
300354 return FALSE;
301355 }
356
357 void
358 browser_update_fs_options (struct browser *browser)
359 {
360 gtk_widget_set_visible (browser->add_dir_button,
361 browser->fs_ops && browser->fs_ops->mkdir != NULL);
362 gtk_widget_set_sensitive (browser->refresh_button,
363 browser->fs_ops
364 && browser->fs_ops->readdir != NULL);
365 gtk_widget_set_sensitive (browser->up_button, browser->fs_ops
366 && browser->fs_ops->readdir != NULL);
367 }
368
369 void
370 browser_init (struct browser *browser)
371 {
372 browser->notifier = g_malloc (sizeof (struct notifier));
373 notifier_init (browser->notifier, browser);
374 }
375
376 void
377 browser_destroy (struct browser *browser)
378 {
379 notifier_destroy (browser->notifier);
380 g_free (browser->notifier);
381 if (browser->thread)
382 {
383 g_thread_join (browser->thread);
384 }
385 g_slist_free (browser->sensitive_widgets);
386 }
387
388 void
389 browser_set_options (struct browser *browser)
390 {
391 GtkTreeSortable *sortable =
392 GTK_TREE_SORTABLE (gtk_tree_view_get_model (browser->view));
393
394 if (browser->fs_ops->options & FS_OPTION_SORT_BY_ID)
395 {
396 gtk_tree_sortable_set_sort_func (sortable,
397 BROWSER_LIST_STORE_ID_FIELD,
398 browser_sort_by_id, NULL, NULL);
399 gtk_tree_sortable_set_sort_column_id (sortable,
400 BROWSER_LIST_STORE_ID_FIELD,
401 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
402 }
403 else if (browser->fs_ops->options & FS_OPTION_SORT_BY_NAME)
404 {
405 gtk_tree_sortable_set_sort_func (sortable,
406 BROWSER_LIST_STORE_NAME_FIELD,
407 browser_sort_by_name, NULL, NULL);
408 gtk_tree_sortable_set_sort_column_id (sortable,
409 BROWSER_LIST_STORE_NAME_FIELD,
410 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
411 }
412 else
413 {
414 gtk_tree_sortable_set_sort_column_id (sortable,
415 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
416 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
417 }
418 }
2020 #include <gtk/gtk.h>
2121 #include <libgen.h>
2222 #include "utils.h"
23 #include "notifier.h"
2324
2425 #ifndef BROWSER_H
2526 #define BROWSER_H
2728 #define SIZE_LABEL_LEN 16
2829
2930 #define DIR_ICON "folder-visiting-symbolic"
30 #define FILE_ICON_WAVE "elektroid-wave-symbolic"
31 #define FILE_ICON_DATA "elektroid-data-symbolic"
32 #define FILE_ICON_PRJ "elektroid-project-symbolic"
33 #define FILE_ICON_SND "elektroid-sound-symbolic"
3431
3532 enum browser_list_field
3633 {
3734 BROWSER_LIST_STORE_ICON_FIELD = 0,
38 BROWSER_LIST_STORE_NAME_FIELD,
35 BROWSER_LIST_STORE_NAME_FIELD, //This is the value returned by the funciton se in the get_item_key member in struct fs_operations. It's the filename.
3936 BROWSER_LIST_STORE_SIZE_FIELD,
4037 BROWSER_LIST_STORE_SIZE_STR_FIELD,
4138 BROWSER_LIST_STORE_TYPE_FIELD,
42 BROWSER_LIST_STORE_INDEX_FIELD
39 BROWSER_LIST_STORE_ID_FIELD,
40 BROWSER_LIST_STORE_SLOT_FIELD //This is an optional map of the id (number) to some string like "A1", "001" or "[A:001]" to mimic the device way of numbering the items.
4341 };
4442
4543 struct browser
4644 {
45 const gchar *name;
4746 GSourceFunc check_selection;
4847 GtkTreeView *view;
4948 GtkWidget *up_button;
5655 GtkTreePath *dnd_motion_path;
5756 gint dnd_timeout_function_id;
5857 GString *dnd_data;
59 void (*notify_dir_change) (struct browser *);
6058 const gchar *file_icon;
6159 gchar **extensions;
6260 const struct fs_operations *fs_ops;
63 void *data;
61 struct backend *backend;
6462 gboolean (*check_callback) ();
63 struct notifier *notifier;
64 //Background loading members
65 GSList *sensitive_widgets;
66 GtkWidget *stack;
67 GtkWidget *spinner;
68 GThread *thread;
69 GMutex mutex;
70 gboolean loading;
71 struct item_iterator *iter;
6572 };
6673
67 gint browser_sort_samples (GtkTreeModel *, GtkTreeIter *, GtkTreeIter *,
68 gpointer);
69
70 gint browser_sort_data (GtkTreeModel *, GtkTreeIter *, GtkTreeIter *,
71 gpointer);
72
73 struct item *browser_get_item (GtkTreeModel *, GtkTreeIter *);
74
75 void browser_free_item (struct item *);
74 void browser_set_item (GtkTreeModel *, GtkTreeIter *, struct item *);
7675
7776 gint browser_get_selected_items_count (struct browser *);
7877
9594
9695 gboolean browser_load_dir (gpointer);
9796
97 void browser_update_fs_options (struct browser *);
98
99 void browser_init (struct browser *);
100
101 void browser_destroy (struct browser *);
102
103 void browser_set_options (struct browser *);
104
98105 #endif
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #include <stdio.h>
21 #include <math.h>
22 #include <endian.h>
23 #include <poll.h>
24 #include <zlib.h>
25 #include <libgen.h>
20 #include <glib/gi18n.h>
21 #include "backend.h"
22 #include "local.h"
2623 #include "connector.h"
27 #include "utils.h"
28 #include "sample.h"
29 #include "package.h"
30 #include "../config.h"
24 #include "connectors/elektron.h"
25 #include "connectors/microbrute.h"
26 #include "connectors/cz.h"
27 #include "connectors/sds.h"
28 #include "connectors/efactor.h"
3129
32 #define KB 1024
33 #define BUFF_SIZE (4 * KB)
34 #define RING_BUFF_SIZE (256 * KB)
35 #define DATA_TRANSF_BLOCK_BYTES 0x2000
36 #define OS_TRANSF_BLOCK_BYTES 0x800
37 #define POLL_TIMEOUT 20
38 #define MAX_ZIP_SIZE (128 * 1024 * 1024)
39
40 #define FS_DATA_PRJ_PREFIX "/projects"
41 #define FS_DATA_SND_PREFIX "/soundbanks"
42 #define FS_SAMPLES_START_POS 5
43 #define FS_DATA_START_POS 18
44 #define FS_SAMPLES_SIZE_POS_W 21
45 #define FS_SAMPLES_LAST_FRAME_POS_W 33
46 #define FS_SAMPLES_PAD_RES 22
47 #define ELEKTRON_SAMPLE_INFO_PAD_I32_LEN 10
48
49 struct elektron_sample_info
30 static gint
31 default_handshake (struct backend *backend)
5032 {
51 guint32 type;
52 guint32 sample_len_bytes;
53 guint32 sample_rate;
54 guint32 loop_start;
55 guint32 loop_end;
56 guint32 loop_type;
57 guint32 padding[ELEKTRON_SAMPLE_INFO_PAD_I32_LEN];
58 };
59
60 typedef GByteArray *(*connector_msg_id_func) (guint);
61
62 typedef GByteArray *(*connector_msg_id_len_func) (guint, guint);
63
64 typedef GByteArray *(*connector_msg_path_func) (const gchar *);
65
66 typedef GByteArray *(*connector_msg_path_len_func) (const gchar *, guint);
67
68 typedef GByteArray *(*connector_msg_read_blk_func) (guint, guint, guint);
69
70 typedef GByteArray *(*connector_msg_write_blk_func) (guint, GByteArray *,
71 guint *, guint, void *);
72
73 typedef void (*connector_copy_array) (GByteArray *, GByteArray *);
74
75 typedef gint (*connector_path_func) (struct connector *, const gchar *);
76
77 typedef gint (*connector_src_dst_func) (struct connector *, const gchar *,
78 const gchar *);
79
80 static gint connector_delete_samples_dir (struct connector *, const gchar *);
81
82 static gint connector_read_samples_dir (struct item_iterator *, const gchar *,
83 void *);
84
85 static gint connector_create_samples_dir (const gchar *, void *);
86
87 static gint connector_delete_samples_item (const gchar *, void *);
88
89 static gint connector_move_samples_item (const gchar *, const gchar *,
90 void *);
91
92 static gint connector_download_sample (const gchar *, GByteArray *,
93 struct job_control *, void *);
94
95 static gint connector_upload_sample (const gchar *, GByteArray *,
96 struct job_control *, void *);
97
98 static gint connector_delete_raw_dir (struct connector *, const gchar *);
99
100 static gint connector_read_raw_dir (struct item_iterator *, const gchar *,
101 void *);
102
103 static gint connector_create_raw_dir (const gchar *, void *);
104
105 static gint connector_delete_raw_item (const gchar *, void *);
106
107 static gint connector_move_raw_item (const gchar *, const gchar *, void *);
108
109 static gint connector_download_raw (const gchar *, GByteArray *,
110 struct job_control *, void *);
111
112 static gint connector_upload_raw (const gchar *, GByteArray *,
113 struct job_control *, void *);
114
115 static gint connector_read_data_dir_any (struct item_iterator *,
116 const gchar *, void *);
117
118 static gint connector_read_data_dir_prj (struct item_iterator *,
119 const gchar *, void *);
120
121 static gint connector_read_data_dir_snd (struct item_iterator *,
122 const gchar *, void *);
123
124 static gint connector_move_data_item_any (const gchar *, const gchar *,
125 void *);
126 static gint connector_move_data_item_prj (const gchar *, const gchar *,
127 void *);
128 static gint connector_move_data_item_snd (const gchar *, const gchar *,
129 void *);
130
131 static gint connector_copy_data_item_any (const gchar *, const gchar *,
132 void *);
133
134 static gint connector_copy_data_item_prj (const gchar *, const gchar *,
135 void *);
136
137 static gint connector_copy_data_item_snd (const gchar *, const gchar *,
138 void *);
139
140 static gint connector_clear_data_item_any (const gchar *, void *);
141
142 static gint connector_clear_data_item_prj (const gchar *, void *);
143
144 static gint connector_clear_data_item_snd (const gchar *, void *);
145
146 static gint connector_swap_data_item_any (const gchar *, const gchar *,
147 void *);
148
149 static gint connector_swap_data_item_prj (const gchar *, const gchar *,
150 void *);
151
152 static gint connector_swap_data_item_snd (const gchar *, const gchar *,
153 void *);
154
155 static gint connector_download_data_any (const gchar *, GByteArray *,
156 struct job_control *, void *);
157
158 static gint connector_download_data_snd_pkg (const gchar *, GByteArray *,
159 struct job_control *, void *);
160
161 static gint connector_download_data_prj_pkg (const gchar *, GByteArray *,
162 struct job_control *, void *);
163
164 static gint connector_download_raw_pst_pkg (const gchar *, GByteArray *,
165 struct job_control *, void *);
166
167
168 static gint connector_upload_data_any (const gchar *, GByteArray *,
169 struct job_control *, void *);
170
171 static gint connector_upload_data_prj_pkg (const gchar *, GByteArray *,
172 struct job_control *, void *);
173
174 static gint connector_upload_data_snd_pkg (const gchar *, GByteArray *,
175 struct job_control *, void *);
176
177 static gint connector_upload_raw_pst_pkg (const gchar *, GByteArray *,
178 struct job_control *, void *);
179
180 static gint connector_copy_iterator (struct item_iterator *,
181 struct item_iterator *, gboolean);
182
183 static const guint8 MSG_HEADER[] = { 0xf0, 0, 0x20, 0x3c, 0x10, 0 };
184
185 static const guint8 PING_REQUEST[] = { 0x1 };
186 static const guint8 SOFTWARE_VERSION_REQUEST[] = { 0x2 };
187 static const guint8 DEVICEUID_REQUEST[] = { 0x3 };
188 static const guint8 STORAGEINFO_REQUEST[] = { 0x5 };
189
190 static const guint8 FS_SAMPLE_READ_DIR_REQUEST[] = { 0x10 };
191 static const guint8 FS_SAMPLE_CREATE_DIR_REQUEST[] = { 0x11 };
192 static const guint8 FS_SAMPLE_DELETE_DIR_REQUEST[] = { 0x12 };
193 static const guint8 FS_SAMPLE_DELETE_FILE_REQUEST[] = { 0x20 };
194 static const guint8 FS_SAMPLE_RENAME_FILE_REQUEST[] = { 0x21 };
195 static const guint8 FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST[] =
196 { 0x23, 0, 0, 0, 0, 0, 0, 0, 0 };
197 static const guint8 FS_SAMPLE_OPEN_FILE_READER_REQUEST[] = { 0x30 };
198 static const guint8 FS_SAMPLE_CLOSE_FILE_READER_REQUEST[] = { 0x31 };
199 static const guint8 FS_SAMPLE_READ_FILE_REQUEST[] =
200 { 0x32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
201 static const guint8 FS_SAMPLE_OPEN_FILE_WRITER_REQUEST[] =
202 { 0x40, 0, 0, 0, 0 };
203 static const guint8 FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST[] =
204 { 0x41, 0, 0, 0, 0, 0, 0, 0, 0 };
205 static const guint8 FS_SAMPLE_WRITE_FILE_REQUEST[] =
206 { 0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
207
208 static const guint8 FS_RAW_READ_DIR_REQUEST[] = { 0x14 };
209 static const guint8 FS_RAW_CREATE_DIR_REQUEST[] = { 0x15 };
210 static const guint8 FS_RAW_DELETE_DIR_REQUEST[] = { 0x16 };
211 static const guint8 FS_RAW_DELETE_FILE_REQUEST[] = { 0x24 };
212 static const guint8 FS_RAW_RENAME_FILE_REQUEST[] = { 0x25 };
213 static const guint8 FS_RAW_OPEN_FILE_READER_REQUEST[] = { 0x33 };
214 static const guint8 FS_RAW_CLOSE_FILE_READER_REQUEST[] = { 0x34 };
215 static const guint8 FS_RAW_READ_FILE_REQUEST[] =
216 { 0x35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
217 static const guint8 FS_RAW_OPEN_FILE_WRITER_REQUEST[] = { 0x43, 0, 0, 0, 0 };
218 static const guint8 FS_RAW_CLOSE_FILE_WRITER_REQUEST[] =
219 { 0x44, 0, 0, 0, 0, 0, 0, 0, 0 };
220 static const guint8 FS_RAW_WRITE_FILE_REQUEST[] =
221 { 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
222
223 static const guint8 DATA_LIST_REQUEST[] = { 0x53 };
224 static const guint8 DATA_READ_OPEN_REQUEST[] = { 0x54 };
225 static const guint8 DATA_READ_PARTIAL_REQUEST[] = { 0x55 };
226 static const guint8 DATA_READ_CLOSE_REQUEST[] = { 0x56 };
227 static const guint8 DATA_WRITE_OPEN_REQUEST[] = { 0x57 };
228 static const guint8 DATA_WRITE_PARTIAL_REQUEST[] = { 0x58 };
229 static const guint8 DATA_WRITE_CLOSE_REQUEST[] = { 0x59 };
230 static const guint8 DATA_MOVE_REQUEST[] = { 0x5a };
231 static const guint8 DATA_COPY_REQUEST[] = { 0x5b };
232 static const guint8 DATA_CLEAR_REQUEST[] = { 0x5c };
233 static const guint8 DATA_SWAP_REQUEST[] = { 0x5d };
234 static const guint8 OS_UPGRADE_START_REQUEST[] =
235 { 0x50, 0, 0, 0, 0, 's', 'y', 's', 'e', 'x', '\0', 1 };
236 static const guint8 OS_UPGRADE_WRITE_RESPONSE[] =
237 { 0x51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
238
239 static const gchar *FS_TYPE_NAMES[] = { "+Drive", "RAM" };
240
241 static const struct fs_operations FS_SAMPLES_OPERATIONS = {
242 .fs = FS_SAMPLES,
243 .readdir = connector_read_samples_dir,
244 .mkdir = connector_create_samples_dir,
245 .delete = connector_delete_samples_item,
246 .rename = connector_move_samples_item,
247 .move = connector_move_samples_item,
248 .copy = NULL,
249 .clear = NULL,
250 .swap = NULL,
251 .download = connector_download_sample,
252 .upload = connector_upload_sample,
253 .getid = get_item_name,
254 .load = sample_load,
255 .save = sample_save,
256 .extension = "wav"
257 };
258
259 static const struct fs_operations FS_RAW_ANY_OPERATIONS = {
260 .fs = FS_RAW_ALL,
261 .readdir = connector_read_raw_dir,
262 .mkdir = connector_create_raw_dir,
263 .delete = connector_delete_raw_item,
264 .rename = connector_move_raw_item,
265 .move = connector_move_raw_item,
266 .copy = NULL,
267 .clear = NULL,
268 .swap = NULL,
269 .download = connector_download_raw,
270 .upload = connector_upload_raw,
271 .getid = get_item_name,
272 .load = load_file,
273 .save = save_file,
274 .extension = "raw"
275 };
276
277 static const struct fs_operations FS_RAW_PRESETS_OPERATIONS = {
278 .fs = FS_RAW_PRESETS,
279 .readdir = connector_read_raw_dir,
280 .mkdir = connector_create_raw_dir,
281 .delete = connector_delete_raw_item,
282 .rename = connector_move_raw_item,
283 .move = connector_move_raw_item,
284 .copy = NULL,
285 .clear = NULL,
286 .swap = NULL,
287 .download = connector_download_raw_pst_pkg,
288 .upload = connector_upload_raw_pst_pkg,
289 .getid = get_item_name,
290 .load = load_file,
291 .save = save_file,
292 .extension = "pst"
293 };
294
295 static const struct fs_operations FS_DATA_ANY_OPERATIONS = {
296 .fs = FS_DATA_ALL,
297 .readdir = connector_read_data_dir_any,
298 .mkdir = NULL,
299 .delete = connector_clear_data_item_any,
300 .rename = NULL,
301 .move = connector_move_data_item_any,
302 .copy = connector_copy_data_item_any,
303 .clear = connector_clear_data_item_any,
304 .swap = connector_swap_data_item_any,
305 .download = connector_download_data_any,
306 .upload = connector_upload_data_any,
307 .getid = get_item_index,
308 .load = load_file,
309 .save = save_file,
310 .extension = "data"
311 };
312
313 static const struct fs_operations FS_DATA_PRJ_OPERATIONS = {
314 .fs = FS_DATA_PRJ,
315 .readdir = connector_read_data_dir_prj,
316 .mkdir = NULL,
317 .delete = connector_clear_data_item_prj,
318 .rename = NULL,
319 .move = connector_move_data_item_prj,
320 .copy = connector_copy_data_item_prj,
321 .clear = connector_clear_data_item_prj,
322 .swap = connector_swap_data_item_prj,
323 .download = connector_download_data_prj_pkg,
324 .upload = connector_upload_data_prj_pkg,
325 .getid = get_item_index,
326 .load = load_file,
327 .save = save_file,
328 .extension = "prj"
329 };
330
331 static const struct fs_operations FS_DATA_SND_OPERATIONS = {
332 .fs = FS_DATA_SND,
333 .readdir = connector_read_data_dir_snd,
334 .mkdir = NULL,
335 .delete = connector_clear_data_item_snd,
336 .rename = NULL,
337 .move = connector_move_data_item_snd,
338 .copy = connector_copy_data_item_snd,
339 .clear = connector_clear_data_item_snd,
340 .swap = connector_swap_data_item_snd,
341 .download = connector_download_data_snd_pkg,
342 .upload = connector_upload_data_snd_pkg,
343 .getid = get_item_index,
344 .load = load_file,
345 .save = save_file,
346 .extension = "snd"
347 };
348
349 static const struct fs_operations *FS_OPERATIONS[] = {
350 &FS_SAMPLES_OPERATIONS, &FS_RAW_ANY_OPERATIONS, &FS_RAW_PRESETS_OPERATIONS,
351 &FS_DATA_ANY_OPERATIONS, &FS_DATA_PRJ_OPERATIONS, &FS_DATA_SND_OPERATIONS
352 };
353
354 static const int FS_OPERATIONS_N =
355 sizeof (FS_OPERATIONS) / sizeof (struct fs_operations *);
356
357 static enum item_type connector_get_path_type (struct connector *,
358 const gchar *,
359 fs_init_iter_func);
360
361 static void
362 connector_free_iterator_data (void *iter_data)
363 {
364 struct connector_iterator_data *data = iter_data;
365
366 if (!data->cached)
33 backend->type = BE_TYPE_MIDI;
34 backend->device_desc.filesystems = 0;
35 backend->fs_ops = NULL;
36 backend->destroy_data = backend_destroy_data;
37 if (strlen (backend->device_name))
36738 {
368 free_msg (data->msg);
369 }
370 g_free (data);
371 }
372
373 const struct fs_operations *
374 connector_get_fs_operations (enum connector_fs fs)
375 {
376 const struct fs_operations *fs_operations = NULL;
377 for (int i = 0; i < FS_OPERATIONS_N; i++)
378 {
379 if (FS_OPERATIONS[i]->fs == fs)
380 {
381 fs_operations = FS_OPERATIONS[i];
382 break;
383 }
384 }
385 return fs_operations;
386 }
387
388 static inline gchar *
389 connector_get_utf8 (const gchar * s)
390 {
391 return g_convert (s, -1, "UTF8", "CP1252", NULL, NULL, NULL);
392 }
393
394 static inline gchar *
395 connector_get_cp1252 (const gchar * s)
396 {
397 return g_convert (s, -1, "CP1252", "UTF8", NULL, NULL, NULL);
398 }
399
400 static inline guint8
401 connector_get_msg_status (const GByteArray * msg)
402 {
403 return msg->data[5];
404 }
405
406 static inline gchar *
407 connector_get_msg_string (const GByteArray * msg)
408 {
409 return (gchar *) & msg->data[6];
410 }
411
412 static guint
413 connector_next_smplrw_entry (struct item_iterator *iter)
414 {
415 guint32 *data32;
416 gchar *name_cp1252;
417 struct connector_iterator_data *data = iter->data;
418
419 if (iter->item.name != NULL)
420 {
421 g_free (iter->item.name);
422 }
423
424 if (data->pos == data->msg->len)
425 {
426 iter->item.name = NULL;
427 return -ENOENT;
39 gchar *device_name = strdup (backend->device_name);
40 snprintf (backend->device_name, LABEL_MAX, "%s %s", _("MIDI device"),
41 device_name);
42 g_free (device_name);
42843 }
42944 else
43045 {
431 data32 = (guint32 *) & data->msg->data[data->pos];
432 data->hash = be32toh (*data32);
433 data->pos += sizeof (guint32);
434
435 data32 = (guint32 *) & data->msg->data[data->pos];
436 iter->item.size = be32toh (*data32);
437 data->pos += sizeof (guint32);
438
439 data->pos++; //write_protected
440
441 iter->item.type = data->msg->data[data->pos];
442 data->pos++;
443
444 name_cp1252 = (gchar *) & data->msg->data[data->pos];
445 iter->item.name = connector_get_utf8 (name_cp1252);
446 if (data->fs == FS_RAW_ALL && iter->item.type == ELEKTROID_FILE)
447 {
448 //This eliminates the extension ".mc-snd" that the device provides.
449 iter->item.name[strlen (iter->item.name) - 7] = 0;
450 }
451 data->pos += strlen (name_cp1252) + 1;
452
453 iter->item.index = -1;
454
455 return 0;
46 snprintf (backend->device_name, LABEL_MAX, "%s", _("MIDI device"));
45647 }
457 }
458
459 static gint
460 connector_init_iterator (struct item_iterator *iter, GByteArray * msg,
461 iterator_next next, enum connector_fs fs,
462 gboolean cached)
463 {
464 struct connector_iterator_data *data =
465 malloc (sizeof (struct connector_iterator_data));
466
467 data->msg = msg;
468 data->pos = fs == FS_DATA_ALL ? FS_DATA_START_POS : FS_SAMPLES_START_POS;
469 data->fs = fs;
470 data->cached = cached;
471
472 iter->data = data;
473 iter->next = next;
474 iter->free = connector_free_iterator_data;
475 iter->copy = connector_copy_iterator;
476 iter->item.name = NULL;
477 iter->item.index = -1;
478
47948 return 0;
48049 }
48150
482 static gint
483 connector_copy_iterator (struct item_iterator *dst, struct item_iterator *src,
484 gboolean cached)
51 struct connector
48552 {
486 GByteArray *array;
487 struct connector_iterator_data *data = src->data;
488 if (cached)
53 gint (*handshake) (struct backend * backend);
54 const gchar *name;
55 };
56
57 static const struct connector CONNECTOR_ELEKTRON = {
58 .handshake = elektron_handshake,
59 .name = "elektron"
60 };
61
62 static const struct connector CONNECTOR_MICROBRUTE = {
63 .handshake = microbrute_handshake,
64 .name = "microbrute"
65 };
66
67 static const struct connector CONNECTOR_CZ = {
68 .handshake = cz_handshake,
69 .name = "cz"
70 };
71
72 static const struct connector CONNECTOR_SDS = {
73 .handshake = sds_handshake,
74 .name = "sds"
75 };
76
77 static const struct connector CONNECTOR_EFACTOR = {
78 .handshake = efactor_handshake,
79 .name = "efactor"
80 };
81
82 static const struct connector CONNECTOR_DEFAULT = {
83 .handshake = default_handshake,
84 .name = "default"
85 };
86
87 // To speed up detection, connectors that purely rely on the standard device inquiry should go first.
88
89 static const struct connector *CONNECTORS[] = {
90 &CONNECTOR_MICROBRUTE, &CONNECTOR_ELEKTRON, &CONNECTOR_CZ, &CONNECTOR_SDS,
91 &CONNECTOR_EFACTOR, &CONNECTOR_DEFAULT, NULL
92 };
93
94 // A handshake function might return these values:
95 // 0, the device matches the connector.
96 // -ENODEV, the device does not match the connector but we can continue with the next connector.
97 // Other negative errors are allowed but we will not continue with the remaining connectors.
98
99 gint
100 connector_init (struct backend *backend, const gchar * id,
101 const gchar * conn_name,
102 struct sysex_transfer *sysex_transfer)
103 {
104 gboolean active = TRUE;
105 const struct connector **connector;
106 int err = backend_init (backend, id);
107 if (err)
489108 {
490 array = data->msg;
491 }
492 else
493 {
494 array = g_byte_array_sized_new (data->msg->len);
495 g_byte_array_append (array, data->msg->data, data->msg->len);
496 }
497 return connector_init_iterator (dst, array, src->next, data->fs, cached);
498 }
499
500 static GByteArray *
501 connector_decode_payload (const GByteArray * src)
502 {
503 GByteArray *dst;
504 int i, j, k, dst_len;
505 unsigned int shift;
506
507 dst_len = src->len - ceill (src->len / 8.0);
508 dst = g_byte_array_new ();
509 g_byte_array_set_size (dst, dst_len);
510
511 for (i = 0, j = 0; i < src->len; i += 8, j += 7)
512 {
513 shift = 0x40;
514 for (k = 0; k < 7 && i + k + 1 < src->len; k++)
515 {
516 dst->data[j + k] =
517 src->data[i + k + 1] | (src->data[i] & shift ? 0x80 : 0);
518 shift = shift >> 1;
519 }
109 return err;
520110 }
521111
522 return dst;
523 }
112 backend_rx_drain (backend); //This is needed in case of timeout.
524113
525 static GByteArray *
526 connector_encode_payload (const GByteArray * src)
527 {
528 GByteArray *dst;
529 int i, j, k, dst_len;
530 unsigned int accum;
531
532 dst_len = src->len + ceill (src->len / 7.0);
533 dst = g_byte_array_new ();
534 g_byte_array_set_size (dst, dst_len);
535
536 for (i = 0, j = 0; j < src->len; i += 8, j += 7)
114 err = -ENODEV;
115 connector = CONNECTORS;
116 while (*connector)
537117 {
538 accum = 0;
539 for (k = 0; k < 7; k++)
118 if (sysex_transfer)
540119 {
541 accum = accum << 1;
542 if (j + k < src->len)
543 {
544 if (src->data[j + k] & 0x80)
545 {
546 accum |= 1;
547 }
548 dst->data[i + k + 1] = src->data[j + k] & 0x7f;
549 }
550 }
551 dst->data[i] = accum;
552 }
553
554 return dst;
555 }
556
557 static GByteArray *
558 connector_msg_to_raw (const GByteArray * msg)
559 {
560 GByteArray *encoded;
561 GByteArray *sysex = g_byte_array_new ();
562
563 g_byte_array_append (sysex, MSG_HEADER, sizeof (MSG_HEADER));
564 encoded = connector_encode_payload (msg);
565 g_byte_array_append (sysex, encoded->data, encoded->len);
566 free_msg (encoded);
567 g_byte_array_append (sysex, (guint8 *) "\xf7", 1);
568
569 return sysex;
570 }
571
572 static gint
573 connector_get_smplrw_info_from_msg (GByteArray * info_msg, guint32 * id,
574 guint * size)
575 {
576 if (connector_get_msg_status (info_msg))
577 {
578 if (id)
579 {
580 *id = be32toh (*((guint32 *) & info_msg->data[6]));
581 }
582 if (size)
583 {
584 *size = be32toh (*((guint32 *) & info_msg->data[10]));
585 }
586 }
587 else
588 {
589 if (id)
590 {
591 return -EIO;
592 }
593 }
594
595 return 0;
596 }
597
598 static GByteArray *
599 connector_new_msg (const guint8 * data, guint len)
600 {
601 GByteArray *msg = g_byte_array_new ();
602
603 g_byte_array_append (msg, (guchar *) "\0\0\0\0", 4);
604 g_byte_array_append (msg, data, len);
605
606 return msg;
607 }
608
609 static GByteArray *
610 connector_new_msg_uint8 (const guint8 * data, guint len, guint8 type)
611 {
612 GByteArray *msg = connector_new_msg (data, len);
613
614 g_byte_array_append (msg, &type, 1);
615
616 return msg;
617 }
618
619 static GByteArray *
620 connector_new_msg_path (const guint8 * data, guint len, const gchar * path)
621 {
622 GByteArray *msg;
623 gchar *path_cp1252 = connector_get_cp1252 (path);
624
625 if (!path_cp1252)
626 {
627 return NULL;
628 }
629
630 msg = connector_new_msg (data, len);
631 g_byte_array_append (msg, (guchar *) path_cp1252, strlen (path_cp1252) + 1);
632 g_free (path_cp1252);
633
634 return msg;
635 }
636
637 static GByteArray *
638 connector_new_msg_close_common_read (const guint8 * data, guint len, guint id)
639 {
640 guint32 aux32;
641 GByteArray *msg = connector_new_msg (data, len);
642
643 aux32 = htobe32 (id);
644 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
645 return msg;
646 }
647
648 static GByteArray *
649 connector_new_msg_close_sample_read (guint id)
650 {
651 return
652 connector_new_msg_close_common_read (FS_SAMPLE_CLOSE_FILE_READER_REQUEST,
653 sizeof
654 (FS_SAMPLE_CLOSE_FILE_READER_REQUEST),
655 id);
656 }
657
658 static GByteArray *
659 connector_new_msg_close_raw_read (guint id)
660 {
661 return
662 connector_new_msg_close_common_read (FS_RAW_CLOSE_FILE_READER_REQUEST,
663 sizeof
664 (FS_RAW_CLOSE_FILE_READER_REQUEST),
665 id);
666 }
667
668 static GByteArray *
669 connector_new_msg_open_common_write (const guint8 * data, guint len,
670 const gchar * path, guint bytes)
671 {
672 guint32 aux32;
673 GByteArray *msg = connector_new_msg_path (data, len, path);
674
675 aux32 = htobe32 (bytes);
676 memcpy (&msg->data[5], &aux32, sizeof (guint32));
677
678 return msg;
679 }
680
681 static GByteArray *
682 connector_new_msg_open_sample_write (const gchar * path, guint bytes)
683 {
684 return
685 connector_new_msg_open_common_write (FS_SAMPLE_OPEN_FILE_WRITER_REQUEST,
686 sizeof
687 (FS_SAMPLE_OPEN_FILE_WRITER_REQUEST),
688 path,
689 bytes +
690 sizeof (struct
691 elektron_sample_info));
692 }
693
694 static GByteArray *
695 connector_new_msg_open_raw_write (const gchar * path, guint bytes)
696 {
697 return connector_new_msg_open_common_write (FS_RAW_OPEN_FILE_WRITER_REQUEST,
698 sizeof
699 (FS_RAW_OPEN_FILE_WRITER_REQUEST),
700 path, bytes);
701 }
702
703
704 static GByteArray *
705 connector_new_msg_list (const gchar * path, int32_t start_index,
706 int32_t end_index, gboolean all)
707 {
708 guint32 aux32;
709 guint8 aux8;
710 GByteArray *msg = connector_new_msg_path (DATA_LIST_REQUEST,
711 sizeof (DATA_LIST_REQUEST),
712 path);
713
714 aux32 = htobe32 (start_index);
715 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
716 aux32 = htobe32 (end_index);
717 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
718 aux8 = all;
719 g_byte_array_append (msg, (guchar *) & aux8, sizeof (guint8));
720
721 return msg;
722 }
723
724 static GByteArray *
725 connector_new_msg_write_sample_blk (guint id, GByteArray * sample,
726 guint * total, guint seq, void *data)
727 {
728 guint32 aux32;
729 guint16 aux16, *aux16p;
730 int i, consumed, bytes_blk;
731 struct sample_loop_data *sample_loop_data = data;
732 struct elektron_sample_info elektron_sample_info;
733 GByteArray *msg = connector_new_msg (FS_SAMPLE_WRITE_FILE_REQUEST,
734 sizeof (FS_SAMPLE_WRITE_FILE_REQUEST));
735
736
737 aux32 = htobe32 (id);
738 memcpy (&msg->data[5], &aux32, sizeof (guint32));
739 aux32 = htobe32 (DATA_TRANSF_BLOCK_BYTES * seq);
740 memcpy (&msg->data[13], &aux32, sizeof (guint32));
741
742 bytes_blk = DATA_TRANSF_BLOCK_BYTES;
743 consumed = 0;
744
745 if (seq == 0)
746 {
747 elektron_sample_info.type = 0;
748 elektron_sample_info.sample_len_bytes = htobe32 (sample->len);
749 elektron_sample_info.sample_rate = htobe32 (ELEKTRON_SAMPLE_RATE);
750 elektron_sample_info.loop_start = htobe32 (sample_loop_data->start);
751 elektron_sample_info.loop_end = htobe32 (sample_loop_data->end);
752 elektron_sample_info.loop_type = htobe32 (ELEKTRON_LOOP_TYPE);
753 memset (&elektron_sample_info.padding, 0,
754 sizeof (guint32) * ELEKTRON_SAMPLE_INFO_PAD_I32_LEN);
755
756 g_byte_array_append (msg, (guchar *) & elektron_sample_info,
757 sizeof (struct elektron_sample_info));
758
759 consumed = sizeof (struct elektron_sample_info);
760 bytes_blk -= consumed;
761 }
762
763 i = 0;
764 aux16p = (guint16 *) & sample->data[*total];
765 while (i < bytes_blk && *total < sample->len)
766 {
767 aux16 = htobe16 (*aux16p);
768 g_byte_array_append (msg, (guint8 *) & aux16, sizeof (guint16));
769 aux16p++;
770 (*total) += sizeof (guint16);
771 consumed += sizeof (guint16);
772 i += sizeof (guint16);
773 }
774
775 aux32 = htobe32 (consumed);
776 memcpy (&msg->data[9], &aux32, sizeof (guint32));
777
778 return msg;
779 }
780
781 static GByteArray *
782 connector_new_msg_write_raw_blk (guint id, GByteArray * raw, guint * total,
783 guint seq, void *data)
784 {
785 gint len;
786 guint32 aux32;
787 GByteArray *msg = connector_new_msg (FS_RAW_WRITE_FILE_REQUEST,
788 sizeof (FS_RAW_WRITE_FILE_REQUEST));
789
790 aux32 = htobe32 (id);
791 memcpy (&msg->data[5], &aux32, sizeof (guint32));
792 aux32 = htobe32 (DATA_TRANSF_BLOCK_BYTES * seq);
793 memcpy (&msg->data[13], &aux32, sizeof (guint32));
794
795 len = raw->len - *total;
796 len = len > DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : len;
797 g_byte_array_append (msg, &raw->data[*total], len);
798 (*total) += len;
799
800 aux32 = htobe32 (len);
801 memcpy (&msg->data[9], &aux32, sizeof (guint32));
802
803 return msg;
804 }
805
806 static GByteArray *
807 connector_new_msg_close_common_write (const guint8 * data, guint len,
808 guint id, guint bytes)
809 {
810 guint32 aux32;
811 GByteArray *msg = connector_new_msg (data, len);
812
813 aux32 = htobe32 (id);
814 memcpy (&msg->data[5], &aux32, sizeof (guint32));
815 aux32 = htobe32 (bytes);
816 memcpy (&msg->data[9], &aux32, sizeof (guint32));
817
818 return msg;
819 }
820
821 static GByteArray *
822 connector_new_msg_close_sample_write (guint id, guint bytes)
823 {
824 return
825 connector_new_msg_close_common_write (FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST,
826 sizeof
827 (FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST),
828 id,
829 bytes +
830 sizeof (struct
831 elektron_sample_info));
832 }
833
834 static GByteArray *
835 connector_new_msg_close_raw_write (guint id, guint bytes)
836 {
837 return
838 connector_new_msg_close_common_write (FS_RAW_CLOSE_FILE_WRITER_REQUEST,
839 sizeof
840 (FS_RAW_CLOSE_FILE_WRITER_REQUEST),
841 id, bytes);
842 }
843
844 static GByteArray *
845 connector_new_msg_read_common_blk (const guint8 * data, guint len, guint id,
846 guint start, guint size)
847 {
848 guint32 aux;
849 GByteArray *msg = connector_new_msg (data, len);
850
851 aux = htobe32 (id);
852 memcpy (&msg->data[5], &aux, sizeof (guint32));
853 aux = htobe32 (size);
854 memcpy (&msg->data[9], &aux, sizeof (guint32));
855 aux = htobe32 (start);
856 memcpy (&msg->data[13], &aux, sizeof (guint32));
857
858 return msg;
859 }
860
861 static GByteArray *
862 connector_new_msg_read_sample_blk (guint id, guint start, guint size)
863 {
864 return connector_new_msg_read_common_blk (FS_SAMPLE_READ_FILE_REQUEST,
865 sizeof
866 (FS_SAMPLE_READ_FILE_REQUEST), id,
867 start, size);
868 }
869
870 static GByteArray *
871 connector_new_msg_read_raw_blk (guint id, guint start, guint size)
872 {
873 return connector_new_msg_read_common_blk (FS_RAW_READ_FILE_REQUEST,
874 sizeof (FS_RAW_READ_FILE_REQUEST),
875 id, start, size);
876 }
877
878 static GByteArray *
879 connector_raw_to_msg (GByteArray * sysex)
880 {
881 GByteArray *msg;
882 GByteArray *payload;
883 gint len = sysex->len - sizeof (MSG_HEADER) - 1;
884
885 if (len > 0)
886 {
887 payload = g_byte_array_new ();
888 g_byte_array_append (payload, &sysex->data[sizeof (MSG_HEADER)], len);
889 msg = connector_decode_payload (payload);
890 free_msg (payload);
891 }
892 else
893 {
894 msg = NULL;
895 }
896
897 return msg;
898 }
899
900 static ssize_t
901 connector_tx_raw (struct connector *connector, const guint8 * data, guint len)
902 {
903 ssize_t tx_len;
904
905 if (!connector->outputp)
906 {
907 error_print ("Output port is NULL\n");
908 return -ENOTCONN;
909 }
910
911 snd_rawmidi_read (connector->inputp, NULL, 0); // trigger reading
912
913 tx_len = snd_rawmidi_write (connector->outputp, data, len);
914 if (tx_len < 0)
915 {
916 error_print ("Error while writing to device: %s\n",
917 snd_strerror (tx_len));
918 connector_destroy (connector);
919 }
920 return tx_len;
921 }
922
923 gint
924 connector_tx_sysex (struct connector *connector,
925 struct connector_sysex_transfer *transfer)
926 {
927 ssize_t tx_len;
928 guint total;
929 guint len;
930 guchar *b;
931 gint res = 0;
932
933 transfer->status = SENDING;
934
935 b = transfer->raw->data;
936 total = 0;
937 while (total < transfer->raw->len && transfer->active)
938 {
939 len = transfer->raw->len - total;
940 if (len > BUFF_SIZE)
941 {
942 len = BUFF_SIZE;
120 g_mutex_lock (&sysex_transfer->mutex);
121 active = sysex_transfer->active;
122 g_mutex_unlock (&sysex_transfer->mutex);
943123 }
944124
945 tx_len = connector_tx_raw (connector, b, len);
946 if (tx_len < 0)
125 if (!active)
947126 {
948 res = tx_len;
949 break;
950 }
951 b += len;
952 total += len;
953 }
954
955 transfer->active = FALSE;
956 transfer->status = FINISHED;
957 return res;
958 }
959
960 static gint
961 connector_tx (struct connector *connector, const GByteArray * msg)
962 {
963 gint res;
964 guint16 aux;
965 gchar *text;
966 struct connector_sysex_transfer transfer;
967
968 aux = htobe16 (connector->seq);
969 memcpy (msg->data, &aux, sizeof (guint16));
970 if (connector->seq == USHRT_MAX)
971 {
972 connector->seq = 0;
973 }
974 else
975 {
976 connector->seq++;
977 }
978
979 transfer.active = TRUE;
980 transfer.raw = connector_msg_to_raw (msg);
981
982 res = connector_tx_sysex (connector, &transfer);
983 if (!res)
984 {
985 if (debug_level > 1)
986 {
987 text = debug_get_hex_msg (transfer.raw);
988 debug_print (2, "Raw message sent (%d): %s\n", transfer.raw->len,
989 text);
990 free (text);
127 err = -ECANCELED;
128 goto end;
991129 }
992130
993 text = debug_get_hex_msg (msg);
994 debug_print (1, "Message sent (%d): %s\n", msg->len, text);
995 free (text);
996 }
997
998 free_msg (transfer.raw);
999 return res;
1000 }
1001
1002 void
1003 connector_rx_drain (struct connector *connector)
1004 {
1005 debug_print (2, "Draining buffer...\n");
1006 connector->rx_len = 0;
1007 snd_rawmidi_drain (connector->inputp);
1008 }
1009
1010 static gboolean
1011 connector_is_rt_msg (guint8 * data, guint len)
1012 {
1013 guint i;
1014 guint8 *b;
1015
1016 for (i = 0, b = data; i < len; i++, b++)
1017 {
1018 if (*b < 0xf8) //Not System Real-Time Messages
131 if (conn_name)
1019132 {
1020 return FALSE;
1021 }
1022 }
1023
1024 return TRUE;
1025 }
1026
1027 static ssize_t
1028 connector_rx_raw (struct connector *connector, guint8 * data, guint len,
1029 struct connector_sysex_transfer *transfer)
1030 {
1031 ssize_t rx_len;
1032 guint total_time;
1033 unsigned short revents;
1034 gint err;
1035 gchar *text;
1036
1037 if (!connector->inputp)
1038 {
1039 error_print ("Input port is NULL\n");
1040 return -ENOTCONN;
1041 }
1042
1043 total_time = 0;
1044
1045 while (1)
1046 {
1047 err = poll (connector->pfds, connector->npfds, POLL_TIMEOUT);
1048
1049 if (!transfer->active)
1050 {
1051 return -ENODATA;
1052 }
1053
1054 if (err == 0)
1055 {
1056 total_time += POLL_TIMEOUT;
1057 if (((transfer->batch && transfer->status == RECEIVING)
1058 || !transfer->batch) && transfer->timeout > -1
1059 && total_time >= transfer->timeout)
133 if (!strcmp (conn_name, (*connector)->name))
1060134 {
1061 debug_print (1, "Timeout!\n");
1062 return -ENODATA;
135 debug_print (1, "Testing %s connector...\n",
136 (*connector)->name);
137 err = (*connector)->handshake (backend);
138 if (!err)
139 {
140 debug_print (1, "Using %s connector...\n",
141 (*connector)->name);
142 }
143 return err;
1063144 }
1064 continue;
1065 }
1066
1067 if (err < 0)
1068 {
1069 error_print ("Error while polling. %s.\n", g_strerror (errno));
1070 connector_destroy (connector);
1071 return err;
1072 }
1073
1074 if ((err =
1075 snd_rawmidi_poll_descriptors_revents (connector->inputp,
1076 connector->pfds,
1077 connector->npfds,
1078 &revents)) < 0)
1079 {
1080 error_print ("Error while getting poll events. %s.\n",
1081 snd_strerror (err));
1082 connector_destroy (connector);
1083 return err;
1084 }
1085
1086 if (revents & (POLLERR | POLLHUP))
1087 {
1088 return -ENODATA;
1089 }
1090
1091 if (!(revents & POLLIN))
1092 {
1093 continue;
1094 }
1095
1096 rx_len = snd_rawmidi_read (connector->inputp, data, len);
1097
1098 if (rx_len == -EAGAIN || rx_len == 0)
1099 {
1100 continue;
1101 }
1102
1103 if (rx_len > 0)
1104 {
1105 if (connector_is_rt_msg (data, rx_len))
1106 {
1107 continue;
1108 }
1109 break;
1110 }
1111
1112 if (rx_len < 0)
1113 {
1114 error_print ("Error while reading from device: %s\n",
1115 snd_strerror (rx_len));
1116 connector_destroy (connector);
1117 break;
1118 }
1119
1120 }
1121
1122 if (debug_level > 1)
1123 {
1124 text = debug_get_hex_data (3, data, rx_len);
1125 debug_print (2, "Buffer content (%zu): %s\n", rx_len, text);
1126 free (text);
1127 }
1128
1129 return rx_len;
1130 }
1131
1132 gint
1133 connector_rx_sysex (struct connector *connector,
1134 struct connector_sysex_transfer *transfer)
1135 {
1136 gint i;
1137 guint8 *b;
1138 gint res = 0;
1139
1140 transfer->status = WAITING;
1141 transfer->raw = g_byte_array_new ();
1142
1143 i = 0;
1144 if (connector->rx_len < 0)
1145 {
1146 connector->rx_len = 0;
1147 }
1148 b = connector->buffer;
1149
1150 while (1)
1151 {
1152 if (i == connector->rx_len)
1153 {
1154 connector->rx_len =
1155 connector_rx_raw (connector, connector->buffer, BUFF_SIZE,
1156 transfer);
1157
1158 if (connector->rx_len == -ENODATA)
1159 {
1160 res = -ENODATA;
1161 goto error;
1162 }
1163
1164 if (connector->rx_len < 0)
1165 {
1166 res = -EIO;
1167 goto error;
1168 }
1169
1170 b = connector->buffer;
1171 i = 0;
1172 }
1173
1174 while (i < connector->rx_len && *b != 0xf0)
1175 {
1176 b++;
1177 i++;
1178 }
1179
1180 if (i < connector->rx_len)
1181 {
1182 break;
1183 }
1184 }
1185
1186 g_byte_array_append (transfer->raw, b, 1);
1187 b++;
1188 i++;
1189 transfer->status = RECEIVING;
1190
1191 while (1)
1192 {
1193 if (i == connector->rx_len)
1194 {
1195 connector->rx_len =
1196 connector_rx_raw (connector, connector->buffer, BUFF_SIZE,
1197 transfer);
1198
1199 if (connector->rx_len == -ENODATA && transfer->batch)
1200 {
1201 break;
1202 }
1203
1204 if (connector->rx_len < 0)
1205 {
1206 res = -EIO;
1207 goto error;
1208 }
1209
1210 b = connector->buffer;
1211 i = 0;
1212 }
1213
1214 while (i < connector->rx_len && (*b != 0xf7 || transfer->batch))
1215 {
1216 if (!connector_is_rt_msg (b, 1))
1217 {
1218 g_byte_array_append (transfer->raw, b, 1);
1219 }
1220 b++;
1221 i++;
1222 }
1223
1224 if (i < connector->rx_len)
1225 {
1226 g_byte_array_append (transfer->raw, b, 1);
1227 connector->rx_len = connector->rx_len - i - 1;
1228 if (connector->rx_len > 0)
1229 {
1230 memmove (connector->buffer, &connector->buffer[i + 1],
1231 connector->rx_len);
1232 }
1233 break;
1234 }
1235
1236 }
1237
1238 goto end;
1239
1240 error:
1241 free_msg (transfer->raw);
1242 transfer->raw = NULL;
1243 end:
1244 transfer->active = FALSE;
1245 transfer->status = FINISHED;
1246 return res;
1247 }
1248
1249 static GByteArray *
1250 connector_rx (struct connector *connector)
1251 {
1252 gchar *text;
1253 GByteArray *msg;
1254 struct connector_sysex_transfer transfer;
1255
1256 transfer.active = TRUE;
1257 transfer.timeout = SYSEX_TIMEOUT;
1258 transfer.batch = FALSE;
1259
1260 if (connector_rx_sysex (connector, &transfer))
1261 {
1262 return NULL;
1263 }
1264 while (transfer.raw->len < 12
1265 || (transfer.raw->len >= 12
1266 && (transfer.raw->data[0] != MSG_HEADER[0]
1267 || transfer.raw->data[1] != MSG_HEADER[1]
1268 || transfer.raw->data[2] != MSG_HEADER[2]
1269 || transfer.raw->data[3] != MSG_HEADER[3]
1270 || transfer.raw->data[4] != MSG_HEADER[4]
1271 || transfer.raw->data[5] != MSG_HEADER[5])))
1272 {
1273 if (debug_level > 1)
1274 {
1275 text = debug_get_hex_msg (transfer.raw);
1276 debug_print (2, "Message skipped (%d): %s\n", transfer.raw->len,
1277 text);
1278 free (text);
1279 }
1280 free_msg (transfer.raw);
1281
1282 transfer.active = TRUE;
1283 if (connector_rx_sysex (connector, &transfer))
1284 {
1285 return NULL;
1286 }
1287 }
1288
1289 if (debug_level > 1)
1290 {
1291 text = debug_get_hex_msg (transfer.raw);
1292 debug_print (2, "Raw message received (%d): %s\n", transfer.raw->len,
1293 text);
1294 free (text);
1295 }
1296
1297 msg = connector_raw_to_msg (transfer.raw);
1298 if (msg)
1299 {
1300 text = debug_get_hex_msg (msg);
1301 debug_print (1, "Message received (%d): %s\n", msg->len, text);
1302 free (text);
1303 }
1304
1305 free_msg (transfer.raw);
1306 return msg;
1307 }
1308
1309 static GByteArray *
1310 connector_tx_and_rx (struct connector *connector, GByteArray * tx_msg)
1311 {
1312 ssize_t len;
1313 GByteArray *rx_msg;
1314
1315 g_mutex_lock (&connector->mutex);
1316
1317 connector_rx_drain (connector);
1318
1319 len = connector_tx (connector, tx_msg);
1320 if (len < 0)
1321 {
1322 rx_msg = NULL;
1323 goto cleanup;
1324 }
1325
1326 rx_msg = connector_rx (connector);
1327
1328 cleanup:
1329 free_msg (tx_msg);
1330 g_mutex_unlock (&connector->mutex);
1331 return rx_msg;
1332 }
1333
1334 static gint
1335 connector_read_common_dir (struct item_iterator *iter, const gchar * dir,
1336 void *data, const guint8 msg[], int size,
1337 fs_init_iter_func init_iter, enum connector_fs fs)
1338 {
1339 gboolean cache;
1340 GByteArray *tx_msg;
1341 GByteArray *rx_msg;
1342 struct connector *connector = data;
1343
1344 g_mutex_lock (&connector->mutex);
1345 cache = connector->dir_cache != NULL;
1346 rx_msg = cache ? g_hash_table_lookup (connector->dir_cache, dir) : NULL;
1347 g_mutex_unlock (&connector->mutex);
1348
1349 if (!rx_msg)
1350 {
1351 tx_msg = connector_new_msg_path (msg, size, dir);
1352 if (!tx_msg)
1353 {
1354 return -EINVAL;
1355 }
1356
1357 rx_msg = connector_tx_and_rx (connector, tx_msg);
1358 if (!rx_msg)
1359 {
1360 return -EIO;
1361 }
1362
1363 g_mutex_lock (&connector->mutex);
1364 cache = connector->dir_cache != NULL;
1365 if (cache)
1366 {
1367 gchar *key = g_strdup (dir);
1368 g_hash_table_insert (connector->dir_cache, key, rx_msg);
1369 }
1370 g_mutex_unlock (&connector->mutex);
1371
1372 if (rx_msg->len == 5
1373 && connector_get_path_type (connector, dir,
1374 init_iter) != ELEKTROID_DIR)
1375 {
1376 if (!cache)
1377 {
1378 free_msg (rx_msg);
1379 }
1380 return -ENOTDIR;
1381 }
1382 }
1383
1384 return connector_init_iterator (iter, rx_msg, connector_next_smplrw_entry,
1385 fs, cache);
1386 }
1387
1388 static gint
1389 connector_read_samples_dir (struct item_iterator *iter, const gchar * dir,
1390 void *data)
1391 {
1392 return connector_read_common_dir (iter, dir, data,
1393 FS_SAMPLE_READ_DIR_REQUEST,
1394 sizeof (FS_SAMPLE_READ_DIR_REQUEST),
1395 connector_read_samples_dir, FS_SAMPLES);
1396 }
1397
1398 static gint
1399 connector_read_raw_dir (struct item_iterator *iter, const gchar * dir,
1400 void *data)
1401 {
1402 return connector_read_common_dir (iter, dir, data, FS_RAW_READ_DIR_REQUEST,
1403 sizeof (FS_RAW_READ_DIR_REQUEST),
1404 connector_read_raw_dir, FS_RAW_ALL);
1405 }
1406
1407 static enum item_type
1408 connector_get_path_type (struct connector *connector, const gchar * path,
1409 fs_init_iter_func init_iter)
1410 {
1411 gchar *name_copy;
1412 gchar *parent_copy;
1413 gchar *name;
1414 gchar *parent;
1415 enum item_type res;
1416 struct item_iterator iter;
1417
1418 if (strcmp (path, "/") == 0)
1419 {
1420 return ELEKTROID_DIR;
1421 }
1422
1423 name_copy = strdup (path);
1424 parent_copy = strdup (path);
1425 name = basename (name_copy);
1426 parent = dirname (parent_copy);
1427 res = ELEKTROID_NONE;
1428 if (!init_iter (&iter, parent, connector))
1429 {
1430 while (!next_item_iterator (&iter))
1431 {
1432 if (strcmp (name, iter.item.name) == 0)
1433 {
1434 res = iter.item.type;
1435 break;
1436 }
1437 }
1438 free_item_iterator (&iter);
1439 }
1440
1441 g_free (name_copy);
1442 g_free (parent_copy);
1443 return res;
1444 }
1445
1446 static gint
1447 connector_src_dst_common (struct connector *connector,
1448 const gchar * src, const gchar * dst,
1449 const guint8 * data, guint len)
1450 {
1451 gint res;
1452 GByteArray *rx_msg;
1453 GByteArray *tx_msg = connector_new_msg (data, len);
1454
1455 gchar *dst_cp1252 = connector_get_cp1252 (dst);
1456 if (!dst_cp1252)
1457 {
1458 return -EINVAL;
1459 }
1460
1461 gchar *src_cp1252 = connector_get_cp1252 (src);
1462 if (!src_cp1252)
1463 {
1464 g_free (dst_cp1252);
1465 return -EINVAL;
1466 }
1467
1468 g_byte_array_append (tx_msg, (guchar *) src_cp1252,
1469 strlen (src_cp1252) + 1);
1470 g_byte_array_append (tx_msg, (guchar *) dst_cp1252,
1471 strlen (dst_cp1252) + 1);
1472
1473 g_free (src_cp1252);
1474 g_free (dst_cp1252);
1475
1476 rx_msg = connector_tx_and_rx (connector, tx_msg);
1477 if (!rx_msg)
1478 {
1479 return -EIO;
1480 }
1481 //Response: x, x, x, x, 0xa1, [0 (error), 1 (success)]...
1482 if (connector_get_msg_status (rx_msg))
1483 {
1484 res = 0;
1485 }
1486 else
1487 {
1488 res = -EPERM;
1489 error_print ("%s (%s)\n", snd_strerror (res),
1490 connector_get_msg_string (rx_msg));
1491 }
1492 free_msg (rx_msg);
1493
1494 return res;
1495 }
1496
1497 static gint
1498 connector_rename_sample_file (struct connector *connector, const gchar * src,
1499 const gchar * dst)
1500 {
1501 return connector_src_dst_common (connector, src, dst,
1502 FS_SAMPLE_RENAME_FILE_REQUEST,
1503 sizeof (FS_SAMPLE_RENAME_FILE_REQUEST));
1504 }
1505
1506 static gint
1507 connector_rename_raw_file (struct connector *connector, const gchar * src,
1508 const gchar * dst)
1509 {
1510 return connector_src_dst_common (connector, src, dst,
1511 FS_RAW_RENAME_FILE_REQUEST,
1512 sizeof (FS_RAW_RENAME_FILE_REQUEST));
1513 }
1514
1515 static gint
1516 connector_move_common_item (const gchar * src, const gchar * dst, void *data,
1517 fs_init_iter_func init_iter,
1518 connector_src_dst_func mv, fs_path_func mkdir,
1519 connector_path_func rmdir)
1520 {
1521 enum item_type type;
1522 gint res;
1523 gchar *src_plus;
1524 gchar *dst_plus;
1525 struct item_iterator iter;
1526 struct connector *connector = data;
1527
1528 //Renaming is not implemented for directories so we need to implement it.
1529
1530 debug_print (1, "Renaming remotely from %s to %s...\n", src, dst);
1531
1532 type = connector_get_path_type (connector, src, init_iter);
1533 if (type == ELEKTROID_FILE)
1534 {
1535 return mv (connector, src, dst);
1536 }
1537 else if (type == ELEKTROID_DIR)
1538 {
1539 res = mkdir (dst, connector);
1540 if (res)
1541 {
1542 return res;
1543 }
1544 if (!init_iter (&iter, src, connector))
1545 {
1546 while (!next_item_iterator (&iter) && !res)
1547 {
1548 src_plus = chain_path (src, iter.item.name);
1549 dst_plus = chain_path (dst, iter.item.name);
1550 res =
1551 connector_move_common_item (src_plus, dst_plus, connector,
1552 init_iter, mv, mkdir, rmdir);
1553 free (src_plus);
1554 free (dst_plus);
1555 }
1556 free_item_iterator (&iter);
1557 }
1558 if (!res)
1559 {
1560 res = rmdir (connector, src);
1561 }
1562 return res;
1563 }
1564 else
1565 {
1566 return -EBADF;
1567 }
1568 }
1569
1570 static gint
1571 connector_path_common (struct connector *connector, const gchar * path,
1572 const guint8 * template, gint size)
1573 {
1574 gint res;
1575 GByteArray *rx_msg;
1576 GByteArray *tx_msg;
1577
1578 tx_msg = connector_new_msg_path (template, size, path);
1579 if (!tx_msg)
1580 {
1581 return -EINVAL;
1582 }
1583
1584 rx_msg = connector_tx_and_rx (connector, tx_msg);
1585 if (!rx_msg)
1586 {
1587 return -EIO;
1588 }
1589 //Response: x, x, x, x, 0xX0, [0 (error), 1 (success)]...
1590 if (connector_get_msg_status (rx_msg))
1591 {
1592 res = 0;
1593 }
1594 else
1595 {
1596 res = -EPERM;
1597 error_print ("%s (%s)\n", snd_strerror (res),
1598 connector_get_msg_string (rx_msg));
1599 }
1600 free_msg (rx_msg);
1601
1602 return res;
1603 }
1604
1605 static gint
1606 connector_delete_sample (struct connector *connector, const gchar * path)
1607 {
1608 return connector_path_common (connector, path,
1609 FS_SAMPLE_DELETE_FILE_REQUEST,
1610 sizeof (FS_SAMPLE_DELETE_FILE_REQUEST));
1611 }
1612
1613 static gint
1614 connector_delete_samples_dir (struct connector *connector, const gchar * path)
1615 {
1616 return connector_path_common (connector, path, FS_SAMPLE_DELETE_DIR_REQUEST,
1617 sizeof (FS_SAMPLE_DELETE_DIR_REQUEST));
1618 }
1619
1620 //This adds back the extension ".mc-snd" that the device provides.
1621 static gchar *
1622 connector_add_ext_to_mc_snd (const gchar * path)
1623 {
1624 gchar *path_with_ext = malloc (PATH_MAX);
1625 snprintf (path_with_ext, PATH_MAX, "%s%s", path, ".mc-snd");
1626 return path_with_ext;
1627 }
1628
1629 static gint
1630 connector_delete_raw (struct connector *connector, const gchar * path)
1631 {
1632 gint ret;
1633 gchar *path_with_ext = connector_add_ext_to_mc_snd (path);
1634 ret = connector_path_common (connector, path_with_ext,
1635 FS_RAW_DELETE_FILE_REQUEST,
1636 sizeof (FS_RAW_DELETE_FILE_REQUEST));
1637 g_free (path_with_ext);
1638 return ret;
1639 }
1640
1641 static gint
1642 connector_delete_raw_dir (struct connector *connector, const gchar * path)
1643 {
1644 return connector_path_common (connector, path, FS_RAW_DELETE_DIR_REQUEST,
1645 sizeof (FS_RAW_DELETE_DIR_REQUEST));
1646 }
1647
1648 static gint
1649 connector_move_samples_item (const gchar * src, const gchar * dst, void *data)
1650 {
1651 return connector_move_common_item (src, dst, data,
1652 connector_read_samples_dir,
1653 connector_rename_sample_file,
1654 connector_create_samples_dir,
1655 connector_delete_samples_dir);
1656 }
1657
1658 static gint
1659 connector_move_raw_item (const gchar * src, const gchar * dst, void *data)
1660 {
1661 gint ret;
1662 gchar *src_with_ext = connector_add_ext_to_mc_snd (src);
1663 ret = connector_move_common_item (src_with_ext, dst, data,
1664 connector_read_raw_dir,
1665 connector_rename_raw_file,
1666 connector_create_raw_dir,
1667 connector_delete_raw_dir);
1668 g_free (src_with_ext);
1669 return ret;
1670 }
1671
1672 static gint
1673 connector_delete_common_item (const gchar * path, void *data,
1674 fs_init_iter_func init_iter,
1675 connector_path_func rmdir,
1676 connector_path_func rm)
1677 {
1678 enum item_type type;
1679 gchar *new_path;
1680 struct item_iterator iter;
1681 struct connector *connector = data;
1682 gint res;
1683
1684 type = connector_get_path_type (connector, path, init_iter);
1685 if (type == ELEKTROID_FILE)
1686 {
1687 return rm (connector, path);
1688 }
1689 else if (type == ELEKTROID_DIR)
1690 {
1691 debug_print (1, "Deleting %s samples dir...\n", path);
1692
1693 if (init_iter (&iter, path, connector))
1694 {
1695 error_print ("Error while opening samples dir %s dir\n", path);
1696145 }
1697146 else
1698147 {
1699 res = 0;
1700 while (!res && !next_item_iterator (&iter))
148 debug_print (1, "Testing %s connector...\n", (*connector)->name);
149 err = (*connector)->handshake (backend);
150 if (err && err != -ENODEV)
1701151 {
1702 new_path = chain_path (path, iter.item.name);
1703 res = res
1704 || connector_delete_common_item (new_path, connector,
1705 init_iter, rmdir, rm);
1706 free (new_path);
152 return err;
1707153 }
1708 free_item_iterator (&iter);
154
155 if (!err)
156 {
157 debug_print (1, "Using %s connector...\n", (*connector)->name);
158 return 0;
159 }
160
161 backend_rx_drain (backend);
1709162 }
1710 return res || rmdir (connector, path);
1711 }
1712 else
1713 {
1714 return -EBADF;
1715 }
1716 }
1717
1718 static gint
1719 connector_delete_samples_item (const gchar * path, void *data)
1720 {
1721 return connector_delete_common_item (path, data,
1722 connector_read_samples_dir,
1723 connector_delete_samples_dir,
1724 connector_delete_sample);
1725 }
1726
1727 static gint
1728 connector_delete_raw_item (const gchar * path, void *data)
1729 {
1730 return connector_delete_common_item (path, data,
1731 connector_read_raw_dir,
1732 connector_delete_raw_dir,
1733 connector_delete_raw);
1734 }
1735
1736 static gint
1737 connector_upload_smplrw (const gchar * path, GByteArray * input,
1738 struct job_control *control, void *data,
1739 connector_msg_path_len_func new_msg_open_write,
1740 connector_msg_write_blk_func new_msg_write_blk,
1741 connector_msg_id_len_func new_msg_close_write)
1742 {
1743 struct connector *connector = data;
1744 GByteArray *tx_msg;
1745 GByteArray *rx_msg;
1746 guint transferred;
1747 guint32 id;
1748 int i;
1749 gboolean active;
1750 gint res = 0;
1751
1752 //If the file already exists the device makes no difference between creating a new file and creating an already existent file.
1753 //Also, the new file would be discarded if an upload is not completed.
1754
1755 tx_msg = new_msg_open_write (path, input->len);
1756 if (!tx_msg)
1757 {
1758 return -EINVAL;
163 connector++;
1759164 }
1760165
1761 rx_msg = connector_tx_and_rx (connector, tx_msg);
1762 if (!rx_msg)
1763 {
1764 return -EIO;
1765 }
1766
1767 //Response: x, x, x, x, 0xc0, [0 (error), 1 (success)], id, frames
1768 res = connector_get_smplrw_info_from_msg (rx_msg, &id, NULL);
1769 if (res)
1770 {
1771 error_print ("%s (%s)\n", snd_strerror (res),
1772 connector_get_msg_string (rx_msg));
1773 free_msg (rx_msg);
1774 return res;
1775 }
1776 free_msg (rx_msg);
1777
1778 transferred = 0;
1779 i = 0;
1780 if (control)
1781 {
1782 g_mutex_lock (&control->mutex);
1783 active = control->active;
1784 g_mutex_unlock (&control->mutex);
1785 }
1786 else
1787 {
1788 active = TRUE;
1789 }
1790
1791 while (transferred < input->len && active)
1792 {
1793 tx_msg = new_msg_write_blk (id, input, &transferred, i, control->data);
1794 rx_msg = connector_tx_and_rx (connector, tx_msg);
1795 if (!rx_msg)
1796 {
1797 return -EIO;
1798 }
1799 //Response: x, x, x, x, 0xc2, [0 (error), 1 (success)]...
1800 if (!connector_get_msg_status (rx_msg))
1801 {
1802 error_print ("Unexpected status\n");
1803 }
1804 free_msg (rx_msg);
1805 i++;
1806
1807 if (control)
1808 {
1809 set_job_control_progress (control,
1810 transferred / (double) input->len);
1811 g_mutex_lock (&control->mutex);
1812 active = control->active;
1813 g_mutex_unlock (&control->mutex);
1814 }
1815
1816 usleep (REST_TIME);
1817 }
1818
1819 debug_print (2, "%d bytes sent\n", transferred);
1820
1821 if (active)
1822 {
1823 tx_msg = new_msg_close_write (id, transferred);
1824 rx_msg = connector_tx_and_rx (connector, tx_msg);
1825 if (!rx_msg)
1826 {
1827 return -EIO;
1828 }
1829 //Response: x, x, x, x, 0xc1, [0 (error), 1 (success)]...
1830 if (!connector_get_msg_status (rx_msg))
1831 {
1832 error_print ("Unexpected status\n");
1833 }
1834 free_msg (rx_msg);
1835 }
1836
1837 return res;
1838 }
1839
1840 static gint
1841 connector_upload_sample_part (const gchar * path, GByteArray * sample,
1842 struct job_control *control, void *data)
1843 {
1844 return connector_upload_smplrw (path, sample, control, data,
1845 connector_new_msg_open_sample_write,
1846 connector_new_msg_write_sample_blk,
1847 connector_new_msg_close_sample_write);
1848 }
1849
1850 static gint
1851 connector_upload_sample (const gchar * path, GByteArray * output,
1852 struct job_control *control, void *data)
1853 {
1854 control->parts = 1;
1855 control->part = 0;
1856 return connector_upload_sample_part (path, output, control, data);
1857 }
1858
1859 static gint
1860 connector_upload_raw (const gchar * path, GByteArray * sample,
1861 struct job_control *control, void *data)
1862 {
1863 return connector_upload_smplrw (path, sample, control, data,
1864 connector_new_msg_open_raw_write,
1865 connector_new_msg_write_raw_blk,
1866 connector_new_msg_close_raw_write);
1867 }
1868
1869 static GByteArray *
1870 connector_new_msg_open_sample_read (const gchar * path)
1871 {
1872 return connector_new_msg_path (FS_SAMPLE_OPEN_FILE_READER_REQUEST,
1873 sizeof
1874 (FS_SAMPLE_OPEN_FILE_READER_REQUEST), path);
1875 }
1876
1877 static GByteArray *
1878 connector_new_msg_open_raw_read (const gchar * path)
1879 {
1880 return connector_new_msg_path (FS_RAW_OPEN_FILE_READER_REQUEST,
1881 sizeof
1882 (FS_RAW_OPEN_FILE_READER_REQUEST), path);
1883 }
1884
1885 static void
1886 connector_copy_sample_data (GByteArray * input, GByteArray * output)
1887 {
1888 gint i;
1889 gint16 v;
1890 gint16 *frame = (gint16 *) input->data;
1891
1892 for (i = 0; i < input->len; i += sizeof (gint16))
1893 {
1894 v = be16toh (*frame);
1895 g_byte_array_append (output, (guint8 *) & v, sizeof (gint16));
1896 frame++;
1897 }
1898 }
1899
1900 static void
1901 connector_copy_raw_data (GByteArray * input, GByteArray * output)
1902 {
1903 g_byte_array_append (output, input->data, input->len);
1904 }
1905
1906 static gint
1907 connector_download_smplrw (const gchar * path, GByteArray * output,
1908 struct job_control *control, void *data,
1909 connector_msg_path_func new_msg_open_read,
1910 guint read_offset,
1911 connector_msg_read_blk_func new_msg_read_blk,
1912 connector_msg_id_func new_msg_close_read,
1913 connector_copy_array copy_array)
1914 {
1915 struct connector *connector = data;
1916 struct sample_loop_data *sample_loop_data;
1917 struct elektron_sample_info *elektron_sample_info;
1918 GByteArray *tx_msg;
1919 GByteArray *rx_msg;
1920 GByteArray *array;
1921 guint32 id;
1922 guint frames;
1923 guint next_block_start;
1924 guint req_size;
1925 guint offset;
1926 gboolean active;
1927 gint res;
1928
1929 tx_msg = new_msg_open_read (path);
1930 if (!tx_msg)
1931 {
1932 return -EINVAL;
1933 }
1934
1935 rx_msg = connector_tx_and_rx (connector, tx_msg);
1936 if (!rx_msg)
1937 {
1938 return -EIO;
1939 }
1940 res = connector_get_smplrw_info_from_msg (rx_msg, &id, &frames);
1941 if (res)
1942 {
1943 error_print ("%s (%s)\n", snd_strerror (res),
1944 connector_get_msg_string (rx_msg));
1945 free_msg (rx_msg);
1946 return res;
1947 }
1948 free_msg (rx_msg);
1949
1950 debug_print (2, "%d frames to download\n", frames);
1951
1952 if (control)
1953 {
1954 g_mutex_lock (&control->mutex);
1955 active = control->active;
1956 g_mutex_unlock (&control->mutex);
1957 }
1958 else
1959 {
1960 active = TRUE;
1961 }
1962
1963 array = g_byte_array_new ();
1964 res = 0;
1965 next_block_start = 0;
1966 offset = read_offset;
1967 control->data = NULL;
1968 while (next_block_start < frames && active)
1969 {
1970 req_size =
1971 frames - next_block_start >
1972 DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : frames -
1973 next_block_start;
1974 tx_msg = new_msg_read_blk (id, next_block_start, req_size);
1975 rx_msg = connector_tx_and_rx (connector, tx_msg);
1976 if (!rx_msg)
1977 {
1978 res = -EIO;
1979 goto cleanup;
1980 }
1981 g_byte_array_append (array, &rx_msg->data[FS_SAMPLES_PAD_RES + offset],
1982 req_size - offset);
1983
1984 next_block_start += req_size;
1985 //Only in the first iteration. It has no effect for the raw filesystem (M:C) as offset is 0.
1986 if (offset)
1987 {
1988 offset = 0;
1989 elektron_sample_info =
1990 (struct elektron_sample_info *) &rx_msg->data[FS_SAMPLES_PAD_RES];
1991 sample_loop_data = malloc (sizeof (struct elektron_sample_info));
1992 sample_loop_data->start =
1993 be32toh (elektron_sample_info->loop_start);
1994 sample_loop_data->end = be32toh (elektron_sample_info->loop_end);
1995 control->data = sample_loop_data;
1996 debug_print (2, "Loop start at %d, loop end at %d\n",
1997 sample_loop_data->start, sample_loop_data->end);
1998 }
1999
2000 free_msg (rx_msg);
2001
2002 if (control)
2003 {
2004 set_job_control_progress (control,
2005 next_block_start / (double) frames);
2006 g_mutex_lock (&control->mutex);
2007 active = control->active;
2008 g_mutex_unlock (&control->mutex);
2009 }
2010
2011 usleep (REST_TIME);
2012 }
2013
2014 debug_print (2, "%d bytes received\n", next_block_start);
2015
2016 if (active)
2017 {
2018 copy_array (array, output);
2019 }
2020 else
2021 {
2022 res = -1;
2023 }
2024
2025 tx_msg = new_msg_close_read (id);
2026 rx_msg = connector_tx_and_rx (connector, tx_msg);
2027 if (!rx_msg)
2028 {
2029 res = -EIO;
2030 goto cleanup;
2031 }
2032 //Response: x, x, x, x, 0xb1, 00 00 00 0a 00 01 65 de (sample id and received bytes)
2033 free_msg (rx_msg);
2034
2035 cleanup:
2036 free_msg (array);
2037 if (res)
2038 {
2039 g_free (control->data);
2040 }
2041 return res;
2042 }
2043
2044 static gint
2045 connector_download_sample_part (const gchar * path, GByteArray * output,
2046 struct job_control *control, void *data)
2047 {
2048 return connector_download_smplrw (path, output, control, data,
2049 connector_new_msg_open_sample_read,
2050 sizeof
2051 (struct elektron_sample_info),
2052 connector_new_msg_read_sample_blk,
2053 connector_new_msg_close_sample_read,
2054 connector_copy_sample_data);
2055 }
2056
2057 static gint
2058 connector_download_sample (const gchar * path, GByteArray * output,
2059 struct job_control *control, void *data)
2060 {
2061 control->parts = 1;
2062 control->part = 0;
2063 return connector_download_sample_part (path, output, control, data);
2064 }
2065
2066 static gint
2067 connector_download_raw (const gchar * path, GByteArray * output,
2068 struct job_control *control, void *data)
2069 {
2070 gint ret;
2071 gchar *path_with_ext = connector_add_ext_to_mc_snd (path);
2072 ret = connector_download_smplrw (path_with_ext, output, control, data,
2073 connector_new_msg_open_raw_read,
2074 0,
2075 connector_new_msg_read_raw_blk,
2076 connector_new_msg_close_raw_read,
2077 connector_copy_raw_data);
2078 g_free (path_with_ext);
2079 return ret;
2080 }
2081
2082 static gint
2083 connector_create_samples_dir (const gchar * path, void *data)
2084 {
2085 struct connector *connector = data;
2086 return connector_path_common (connector, path, FS_SAMPLE_CREATE_DIR_REQUEST,
2087 sizeof (FS_SAMPLE_CREATE_DIR_REQUEST));
2088 }
2089
2090 static gint
2091 connector_create_raw_dir (const gchar * path, void *data)
2092 {
2093 struct connector *connector = data;
2094 return connector_path_common (connector, path, FS_RAW_CREATE_DIR_REQUEST,
2095 sizeof (FS_RAW_CREATE_DIR_REQUEST));
2096 }
2097
2098 static GByteArray *
2099 connector_new_msg_upgrade_os_start (guint size)
2100 {
2101 GByteArray *msg = connector_new_msg (OS_UPGRADE_START_REQUEST,
2102 sizeof (OS_UPGRADE_START_REQUEST));
2103
2104 memcpy (&msg->data[5], &size, sizeof (guint32));
2105
2106 return msg;
2107 }
2108
2109 static GByteArray *
2110 connector_new_msg_upgrade_os_write (GByteArray * os_data, gint * offset)
2111 {
2112 GByteArray *msg = connector_new_msg (OS_UPGRADE_WRITE_RESPONSE,
2113 sizeof (OS_UPGRADE_WRITE_RESPONSE));
2114 guint len;
2115 guint32 crc;
2116 guint32 aux32;
2117
2118 if (*offset + OS_TRANSF_BLOCK_BYTES < os_data->len)
2119 {
2120 len = OS_TRANSF_BLOCK_BYTES;
2121 }
2122 else
2123 {
2124 len = os_data->len - *offset;
2125 }
2126
2127 crc = crc32 (0xffffffff, &os_data->data[*offset], len);
2128
2129 debug_print (2, "CRC: %0x\n", crc);
2130
2131 aux32 = htobe32 (crc);
2132 memcpy (&msg->data[5], &aux32, sizeof (guint32));
2133 aux32 = htobe32 (len);
2134 memcpy (&msg->data[9], &aux32, sizeof (guint32));
2135 aux32 = htobe32 (*offset);
2136 memcpy (&msg->data[13], &aux32, sizeof (guint32));
2137
2138 g_byte_array_append (msg, &os_data->data[*offset], len);
2139
2140 *offset = *offset + len;
2141
2142 return msg;
2143 }
2144
2145 gint
2146 connector_upgrade_os (struct connector *connector,
2147 struct connector_sysex_transfer *transfer)
2148 {
2149 GByteArray *tx_msg;
2150 GByteArray *rx_msg;
2151 gint8 op;
2152 gint offset;
2153 gint res = 0;
2154
2155 transfer->status = SENDING;
2156
2157 tx_msg = connector_new_msg_upgrade_os_start (transfer->raw->len);
2158 rx_msg = connector_tx_and_rx (connector, tx_msg);
2159
2160 if (!rx_msg)
2161 {
2162 res = -EIO;
2163 goto end;
2164 }
2165 //Response: x, x, x, x, 0xd1, [0 (ok), 1 (error)]...
2166 op = connector_get_msg_status (rx_msg);
2167 if (op)
2168 {
2169 res = -EIO;
2170 error_print ("%s (%s)\n", snd_strerror (res),
2171 connector_get_msg_string (rx_msg));
2172 free_msg (rx_msg);
2173 goto end;
2174 }
2175
2176 free_msg (rx_msg);
2177
2178 offset = 0;
2179 while (offset < transfer->raw->len && transfer->active)
2180 {
2181 tx_msg = connector_new_msg_upgrade_os_write (transfer->raw, &offset);
2182 rx_msg = connector_tx_and_rx (connector, tx_msg);
2183
2184 if (!rx_msg)
2185 {
2186 res = -EIO;
2187 break;
2188 }
2189 //Response: x, x, x, x, 0xd1, int32, [0..3]...
2190 op = rx_msg->data[9];
2191 if (op == 1)
2192 {
2193 break;
2194 }
2195 else if (op > 1)
2196 {
2197 res = -EIO;
2198 error_print ("%s (%s)\n", snd_strerror (res),
2199 connector_get_msg_string (rx_msg));
2200 free_msg (rx_msg);
2201 break;
2202 }
2203
2204 free_msg (rx_msg);
2205
2206 usleep (REST_TIME);
2207 }
166 error_print ("No device recognized\n");
2208167
2209168 end:
2210 transfer->active = FALSE;
2211 transfer->status = FINISHED;
2212 return res;
2213 }
2214
2215 void
2216 connector_destroy (struct connector *connector)
2217 {
2218 int err;
2219
2220 debug_print (1, "Destroying connector...\n");
2221
2222 if (connector->inputp)
2223 {
2224 err = snd_rawmidi_close (connector->inputp);
2225 if (err)
2226 {
2227 error_print ("Error while closing MIDI port: %s\n",
2228 snd_strerror (err));
2229 }
2230 connector->inputp = NULL;
2231 }
2232
2233 if (connector->outputp)
2234 {
2235 err = snd_rawmidi_close (connector->outputp);
2236 if (err)
2237 {
2238 error_print ("Error while closing MIDI port: %s\n",
2239 snd_strerror (err));
2240 }
2241 connector->outputp = NULL;
2242 }
2243
2244 if (connector->device_name)
2245 {
2246 free (connector->device_name);
2247 free (connector->fw_version);
2248 free (connector->overbridge_name);
2249 connector->device_name = NULL;
2250 }
2251
2252 if (connector->buffer)
2253 {
2254 free (connector->buffer);
2255 connector->buffer = NULL;
2256 }
2257
2258 if (connector->pfds)
2259 {
2260 free (connector->pfds);
2261 connector->pfds = NULL;
2262 }
2263
2264 if (connector->dir_cache)
2265 {
2266 g_hash_table_destroy (connector->dir_cache);
2267 connector->dir_cache = NULL;
2268 }
2269
2270 if (connector->device_desc.name)
2271 {
2272 g_free (connector->device_desc.name);
2273 connector->device_desc.name = NULL;
2274 }
2275
2276 if (connector->device_desc.alias)
2277 {
2278 g_free (connector->device_desc.alias);
2279 connector->device_desc.alias = NULL;
2280 }
2281
2282 }
2283
2284 gint
2285 connector_get_storage_stats (struct connector *connector,
2286 enum connector_storage type,
2287 struct connector_storage_stats *statfs)
2288 {
2289 GByteArray *tx_msg;
2290 GByteArray *rx_msg;
2291 gint8 op;
2292 guint64 *data;
2293 int index;
2294 gint res = 0;
2295
2296 tx_msg = connector_new_msg_uint8 (STORAGEINFO_REQUEST,
2297 sizeof (STORAGEINFO_REQUEST), type);
2298 rx_msg = connector_tx_and_rx (connector, tx_msg);
2299 if (!rx_msg)
2300 {
2301 return -EIO;
2302 }
2303
2304 op = connector_get_msg_status (rx_msg);
2305 if (!op)
2306 {
2307 error_print ("%s (%s)\n", snd_strerror (-EIO),
2308 connector_get_msg_string (rx_msg));
2309 free_msg (rx_msg);
2310 return -EIO;
2311 }
2312
2313 index = 0;
2314 for (int i = 0, storage = STORAGE_PLUS_DRIVE; storage <= STORAGE_RAM;
2315 i++, storage <<= 1)
2316 {
2317 if (storage == type)
2318 {
2319 index = i;
2320 }
2321 }
2322
2323 statfs->name = FS_TYPE_NAMES[index];
2324 data = (guint64 *) & rx_msg->data[6];
2325 statfs->bfree = be64toh (*data);
2326 data = (guint64 *) & rx_msg->data[14];
2327 statfs->bsize = be64toh (*data);
2328
2329 free_msg (rx_msg);
2330
2331 return res;
2332 }
2333
2334 gdouble
2335 connector_get_storage_stats_percent (struct connector_storage_stats *statfs)
2336 {
2337 return (statfs->bsize - statfs->bfree) * 100.0 / statfs->bsize;
2338 }
2339
2340 gint
2341 connector_init (struct connector *connector, gint card,
2342 const char *device_filename)
2343 {
2344 gint err;
2345 guint8 id;
2346 GByteArray *tx_msg;
2347 GByteArray *rx_msg;
2348 snd_rawmidi_params_t *params;
2349 gchar name[32];
2350 sprintf (name, "hw:%d", card);
2351 connector->inputp = NULL;
2352 connector->outputp = NULL;
2353 connector->device_name = NULL;
2354 connector->buffer = NULL;
2355 connector->rx_len = 0;
2356 connector->pfds = NULL;
2357 connector->dir_cache = NULL;
2358 connector->device_desc.name = NULL;
2359 connector->device_desc.alias = NULL;
2360 if (card < 0)
2361 {
2362 debug_print (1, "Invalid card\n");
2363 err = -EINVAL;
2364 goto cleanup;
2365 }
2366
2367 debug_print (1, "Initializing connector to '%s'...\n", name);
2368 if ((err =
2369 snd_rawmidi_open (&connector->inputp, &connector->outputp,
2370 name, SND_RAWMIDI_NONBLOCK | SND_RAWMIDI_SYNC)) < 0)
2371 {
2372 error_print ("Error while opening MIDI port: %s\n", g_strerror (err));
2373 goto cleanup;
2374 }
2375
2376 debug_print (1, "Setting blocking mode...\n");
2377 if ((err = snd_rawmidi_nonblock (connector->outputp, 0)) < 0)
2378 {
2379 error_print ("Error while setting blocking mode\n");
2380 goto cleanup;
2381 }
2382 if ((err = snd_rawmidi_nonblock (connector->inputp, 1)) < 0)
2383 {
2384 error_print ("Error while setting blocking mode\n");
2385 goto cleanup;
2386 }
2387
2388 debug_print (1, "Stopping device...\n");
2389 if (snd_rawmidi_write (connector->outputp, "\xfc", 1) < 0)
2390 {
2391 error_print ("Error while stopping device\n");
2392 }
2393
2394 connector->seq = 0;
2395 connector->device_name = malloc (LABEL_MAX);
2396 if (!connector->device_name)
2397 {
2398 goto cleanup;
2399 }
2400
2401 connector->buffer = malloc (sizeof (guint8) * BUFF_SIZE);
2402 if (!connector->buffer)
2403 {
2404 goto cleanup;
2405 }
2406
2407 connector->npfds = snd_rawmidi_poll_descriptors_count (connector->inputp);
2408 connector->pfds = malloc (connector->npfds * sizeof (struct pollfd));
2409 if (!connector->buffer)
2410 {
2411 goto cleanup;
2412 }
2413 snd_rawmidi_poll_descriptors (connector->inputp, connector->pfds,
2414 connector->npfds);
2415 err = snd_rawmidi_params_malloc (&params);
2416 if (err)
2417 {
2418 goto cleanup;
2419 }
2420
2421 err = snd_rawmidi_params_current (connector->inputp, params);
2422 if (err)
2423 {
2424 goto cleanup_params;
2425 }
2426
2427 err =
2428 snd_rawmidi_params_set_buffer_size (connector->inputp, params,
2429 RING_BUFF_SIZE);
2430 if (err)
2431 {
2432 goto cleanup_params;
2433 }
2434
2435 err = snd_rawmidi_params (connector->inputp, params);
2436 if (err)
2437 {
2438 goto cleanup_params;
2439 }
2440
2441 tx_msg = connector_new_msg (PING_REQUEST, sizeof (PING_REQUEST));
2442 rx_msg = connector_tx_and_rx (connector, tx_msg);
2443 if (!rx_msg)
2444 {
2445 err = -EIO;
2446 goto cleanup_params;
2447 }
2448 connector->overbridge_name =
2449 strdup ((gchar *) & rx_msg->data[7 + rx_msg->data[6]]);
2450 id = rx_msg->data[5];
2451 free_msg (rx_msg);
2452 if (load_device_desc (&connector->device_desc, id, device_filename))
2453 {
2454 err = -ENODEV;
2455 goto cleanup_params;
2456 }
2457
2458 tx_msg =
2459 connector_new_msg (SOFTWARE_VERSION_REQUEST,
2460 sizeof (SOFTWARE_VERSION_REQUEST));
2461 rx_msg = connector_tx_and_rx (connector, tx_msg);
2462 if (!rx_msg)
2463 {
2464 err = -EIO;
2465 goto cleanup_params;
2466 }
2467 connector->fw_version = strdup ((gchar *) & rx_msg->data[10]);
2468 free_msg (rx_msg);
2469
2470 if (debug_level > 1)
2471 {
2472 tx_msg =
2473 connector_new_msg (DEVICEUID_REQUEST, sizeof (DEVICEUID_REQUEST));
2474 rx_msg = connector_tx_and_rx (connector, tx_msg);
2475 if (rx_msg)
2476 {
2477 debug_print (1, "UID: %x\n", *((guint32 *) & rx_msg->data[5]));
2478 free_msg (rx_msg);
2479 }
2480 }
2481
2482 snprintf (connector->device_name, LABEL_MAX, "%s %s (%s)",
2483 connector->device_desc.name,
2484 connector->fw_version, connector->overbridge_name);
2485 debug_print (1, "Connected to %s\n", connector->device_name);
2486 err = 0;
2487
2488 cleanup_params:
2489 snd_rawmidi_params_free (params);
2490 cleanup:
2491 if (err)
2492 {
2493 connector_destroy (connector);
2494 }
169 backend_destroy (backend);
2495170 return err;
2496171 }
2497
2498 gboolean
2499 connector_check (struct connector *connector)
2500 {
2501 return (connector->inputp && connector->outputp);
2502 }
2503
2504 static struct connector_system_device *
2505 connector_get_system_device (snd_ctl_t * ctl, int card, int device)
2506 {
2507 snd_rawmidi_info_t *info;
2508 const gchar *name;
2509 const gchar *sub_name;
2510 int subs, subs_in, subs_out;
2511 int sub;
2512 int err;
2513 struct connector_system_device *connector_system_device;
2514
2515 snd_rawmidi_info_alloca (&info);
2516 snd_rawmidi_info_set_device (info, device);
2517 snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_INPUT);
2518 err = snd_ctl_rawmidi_info (ctl, info);
2519 if (err >= 0)
2520 {
2521 subs_in = snd_rawmidi_info_get_subdevices_count (info);
2522 }
2523 else
2524 {
2525 subs_in = 0;
2526 }
2527
2528 snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_OUTPUT);
2529 err = snd_ctl_rawmidi_info (ctl, info);
2530 if (err >= 0)
2531 {
2532 subs_out = snd_rawmidi_info_get_subdevices_count (info);
2533 }
2534 else
2535 {
2536 subs_out = 0;
2537 }
2538
2539 subs = subs_in > subs_out ? subs_in : subs_out;
2540 if (!subs)
2541 {
2542 return NULL;
2543 }
2544
2545 if (subs_in <= 0 || subs_out <= 0)
2546 {
2547 return NULL;
2548 }
2549
2550 sub = 0;
2551 snd_rawmidi_info_set_stream (info, sub < subs_in ?
2552 SND_RAWMIDI_STREAM_INPUT :
2553 SND_RAWMIDI_STREAM_OUTPUT);
2554 snd_rawmidi_info_set_subdevice (info, sub);
2555 err = snd_ctl_rawmidi_info (ctl, info);
2556 if (err < 0)
2557 {
2558 error_print ("Cannot get rawmidi information %d:%d:%d: %s\n",
2559 card, device, sub, snd_strerror (err));
2560 return NULL;
2561 }
2562
2563 name = snd_rawmidi_info_get_name (info);
2564 sub_name = snd_rawmidi_info_get_subdevice_name (info);
2565 if (strncmp (sub_name, "Elektron", 8) == 0)
2566 {
2567 debug_print (1, "Adding hw:%d (%s) %s...\n", card, name, sub_name);
2568 connector_system_device =
2569 malloc (sizeof (struct connector_system_device));
2570 connector_system_device->card = card;
2571 connector_system_device->name = strdup (sub_name);
2572 return connector_system_device;
2573 }
2574 else
2575 {
2576 return NULL;
2577 }
2578 }
2579
2580 static void
2581 connector_fill_card_elektron_devices (gint card, GArray * devices)
2582 {
2583 snd_ctl_t *ctl;
2584 gchar name[32];
2585 gint device;
2586 gint err;
2587 struct connector_system_device *connector_system_device;
2588
2589 sprintf (name, "hw:%d", card);
2590 if ((err = snd_ctl_open (&ctl, name, 0)) < 0)
2591 {
2592 error_print ("Cannot open control for card %d: %s\n",
2593 card, snd_strerror (err));
2594 return;
2595 }
2596 device = -1;
2597 while (!(err = snd_ctl_rawmidi_next_device (ctl, &device)) && device >= 0)
2598 {
2599 connector_system_device =
2600 connector_get_system_device (ctl, card, device);
2601 if (connector_system_device)
2602 {
2603 g_array_append_vals (devices, connector_system_device, 1);
2604 }
2605 }
2606 if (err < 0)
2607 {
2608 error_print ("Cannot determine device number: %s\n",
2609 snd_strerror (err));
2610 }
2611 snd_ctl_close (ctl);
2612 }
2613
2614 GArray *
2615 connector_get_system_devices ()
2616 {
2617 gint card, err;
2618 GArray *devices =
2619 g_array_new (FALSE, FALSE, sizeof (struct connector_system_device));
2620
2621 card = -1;
2622 while (!(err = snd_card_next (&card)) && card >= 0)
2623 {
2624 connector_fill_card_elektron_devices (card, devices);
2625 }
2626 if (err < 0)
2627 {
2628 error_print ("Cannot determine card number: %s\n", snd_strerror (err));
2629 }
2630
2631 return devices;
2632 }
2633
2634 static guint
2635 connector_next_data_entry (struct item_iterator *iter)
2636 {
2637 gchar *name_cp1252;
2638 guint32 *data32;
2639 guint16 *data16;
2640 guint8 type;
2641 guint8 has_children;
2642 struct connector_iterator_data *data = iter->data;
2643
2644 if (iter->item.name != NULL)
2645 {
2646 g_free (iter->item.name);
2647 }
2648
2649 if (data->pos == data->msg->len)
2650 {
2651 iter->item.name = NULL;
2652 return -ENOENT;
2653 }
2654
2655 name_cp1252 = (gchar *) & data->msg->data[data->pos];
2656 iter->item.name = connector_get_utf8 (name_cp1252);
2657 data->pos += strlen (name_cp1252) + 1;
2658 has_children = data->msg->data[data->pos];
2659 data->pos++;
2660 type = data->msg->data[data->pos];
2661 data->pos++;
2662
2663 switch (type)
2664 {
2665 case 1:
2666 iter->item.type = ELEKTROID_DIR;
2667 data->pos += sizeof (guint32); // child entries
2668 iter->item.size = 0;
2669 iter->item.index = -1;
2670 data->operations = 0;
2671 data->has_valid_data = 0;
2672 data->has_metadata = 0;
2673 break;
2674 case 2:
2675 iter->item.type = has_children ? ELEKTROID_DIR : ELEKTROID_FILE;
2676
2677 data32 = (guint32 *) & data->msg->data[data->pos];
2678 iter->item.index = be32toh (*data32); //index
2679 data->pos += sizeof (gint32);
2680
2681 data32 = (guint32 *) & data->msg->data[data->pos];
2682 iter->item.size = be32toh (*data32);
2683 data->pos += sizeof (guint32);
2684
2685 data16 = (guint16 *) & data->msg->data[data->pos];
2686 data->operations = be16toh (*data16);
2687 data->pos += sizeof (guint16);
2688
2689 data->has_valid_data = data->msg->data[data->pos];
2690 data->pos++;
2691
2692 data->has_metadata = data->msg->data[data->pos];
2693 data->pos++;
2694
2695 break;
2696 default:
2697 error_print ("Unrecognized data entry: %d\n", iter->item.type);
2698 break;
2699 }
2700
2701 return 0;
2702 }
2703
2704 static gchar *
2705 connector_add_prefix_to_path (const gchar * dir, const gchar * prefix)
2706 {
2707 gchar *full = malloc (PATH_MAX);
2708
2709 if (prefix)
2710 {
2711 snprintf (full, PATH_MAX, "%s%s", prefix, dir);
2712 }
2713 else
2714 {
2715 strcpy (full, dir);
2716 }
2717
2718 return full;
2719 }
2720
2721 static gint
2722 connector_read_data_dir_prefix (struct item_iterator *iter, const gchar * dir,
2723 void *data, const char *prefix)
2724 {
2725 int res;
2726 GByteArray *tx_msg;
2727 GByteArray *rx_msg;
2728 struct connector *connector = data;
2729 gchar *dir_w_prefix = connector_add_prefix_to_path (dir, prefix);
2730
2731 tx_msg = connector_new_msg_list (dir_w_prefix, 0, 0, 1);
2732 g_free (dir_w_prefix);
2733 if (!tx_msg)
2734 {
2735 return -EINVAL;
2736 }
2737
2738 rx_msg = connector_tx_and_rx (connector, tx_msg);
2739 if (!rx_msg)
2740 {
2741 return -EIO;
2742 }
2743
2744 res = connector_get_msg_status (rx_msg);
2745 if (!res)
2746 {
2747 free_msg (rx_msg);
2748 return -ENOTDIR;
2749 }
2750
2751 return connector_init_iterator (iter, rx_msg, connector_next_data_entry,
2752 FS_DATA_ALL, FALSE);
2753 }
2754
2755 static gint
2756 connector_read_data_dir_any (struct item_iterator *iter, const gchar * dir,
2757 void *data)
2758 {
2759 return connector_read_data_dir_prefix (iter, dir, data, NULL);
2760 }
2761
2762 static gint
2763 connector_read_data_dir_prj (struct item_iterator *iter, const gchar * dir,
2764 void *data)
2765 {
2766 return connector_read_data_dir_prefix (iter, dir, data, FS_DATA_PRJ_PREFIX);
2767 }
2768
2769 static gint
2770 connector_read_data_dir_snd (struct item_iterator *iter, const gchar * dir,
2771 void *data)
2772 {
2773 return connector_read_data_dir_prefix (iter, dir, data, FS_DATA_SND_PREFIX);
2774 }
2775
2776 static gint
2777 connector_dst_src_data_prefix_common (const gchar * src, const gchar * dst,
2778 void *data, const char *prefix,
2779 const guint8 * op_data, guint len)
2780 {
2781 gint res;
2782 struct connector *connector = data;
2783 char *src_w_prefix = connector_add_prefix_to_path (src, prefix);
2784 char *dst_w_prefix = connector_add_prefix_to_path (dst, prefix);
2785
2786 res = connector_src_dst_common (connector, src_w_prefix, dst_w_prefix,
2787 op_data, len);
2788 g_free (src_w_prefix);
2789 g_free (dst_w_prefix);
2790
2791 return res;
2792 }
2793
2794 static gint
2795 connector_move_data_item_prefix (const gchar * src, const gchar * dst,
2796 void *data, const char *prefix)
2797 {
2798 return connector_dst_src_data_prefix_common (src, dst, data, prefix,
2799 DATA_MOVE_REQUEST,
2800 sizeof (DATA_MOVE_REQUEST));
2801 }
2802
2803 static gint
2804 connector_move_data_item_any (const gchar * src, const gchar * dst,
2805 void *data)
2806 {
2807 return connector_move_data_item_prefix (src, dst, data, NULL);
2808 }
2809
2810 static gint
2811 connector_move_data_item_prj (const gchar * src, const gchar * dst,
2812 void *data)
2813 {
2814 return connector_move_data_item_prefix (src, dst, data, FS_DATA_PRJ_PREFIX);
2815 }
2816
2817 static gint
2818 connector_move_data_item_snd (const gchar * src, const gchar * dst,
2819 void *data)
2820 {
2821 return connector_move_data_item_prefix (src, dst, data, FS_DATA_SND_PREFIX);
2822 }
2823
2824 static gint
2825 connector_copy_data_item_prefix (const gchar * src, const gchar * dst,
2826 void *data, const gchar * prefix)
2827 {
2828 return connector_dst_src_data_prefix_common (src, dst, data, prefix,
2829 DATA_COPY_REQUEST,
2830 sizeof (DATA_COPY_REQUEST));
2831 }
2832
2833 static gint
2834 connector_copy_data_item_any (const gchar * src, const gchar * dst,
2835 void *data)
2836 {
2837 return connector_copy_data_item_prefix (src, dst, data, NULL);
2838 }
2839
2840 static gint
2841 connector_copy_data_item_prj (const gchar * src, const gchar * dst,
2842 void *data)
2843 {
2844 return connector_copy_data_item_prefix (src, dst, data, FS_DATA_PRJ_PREFIX);
2845 }
2846
2847 static gint
2848 connector_copy_data_item_snd (const gchar * src, const gchar * dst,
2849 void *data)
2850 {
2851 return connector_copy_data_item_prefix (src, dst, data, FS_DATA_SND_PREFIX);
2852 }
2853
2854 static gint
2855 connector_path_data_prefix_common (const gchar * path,
2856 void *data, const char *prefix,
2857 const guint8 * op_data, guint len)
2858 {
2859 gint res;
2860 struct connector *connector = data;
2861 char *path_w_prefix = connector_add_prefix_to_path (path, prefix);
2862
2863 res = connector_path_common (connector, path_w_prefix, op_data, len);
2864 g_free (path_w_prefix);
2865
2866 return res;
2867 }
2868
2869 static gint
2870 connector_clear_data_item_prefix (const gchar * path, void *data,
2871 const gchar * prefix)
2872 {
2873 return connector_path_data_prefix_common (path, data, prefix,
2874 DATA_CLEAR_REQUEST,
2875 sizeof (DATA_CLEAR_REQUEST));
2876 }
2877
2878 static gint
2879 connector_clear_data_item_any (const gchar * path, void *data)
2880 {
2881 return connector_clear_data_item_prefix (path, data, NULL);
2882 }
2883
2884 static gint
2885 connector_clear_data_item_prj (const gchar * path, void *data)
2886 {
2887 return connector_clear_data_item_prefix (path, data, FS_DATA_PRJ_PREFIX);
2888 }
2889
2890 static gint
2891 connector_clear_data_item_snd (const gchar * path, void *data)
2892 {
2893 return connector_clear_data_item_prefix (path, data, FS_DATA_SND_PREFIX);
2894 }
2895
2896 static gint
2897 connector_swap_data_item_prefix (const gchar * src, const gchar * dst,
2898 void *data, const gchar * prefix)
2899 {
2900 return connector_dst_src_data_prefix_common (src, dst, data, prefix,
2901 DATA_SWAP_REQUEST,
2902 sizeof (DATA_SWAP_REQUEST));
2903 }
2904
2905 static gint
2906 connector_swap_data_item_any (const gchar * src, const gchar * dst,
2907 void *data)
2908 {
2909 return connector_swap_data_item_prefix (src, dst, data, NULL);
2910 }
2911
2912 static gint
2913 connector_swap_data_item_prj (const gchar * src, const gchar * dst,
2914 void *data)
2915 {
2916 return connector_swap_data_item_prefix (src, dst, data, FS_DATA_PRJ_PREFIX);
2917 }
2918
2919 static gint
2920 connector_swap_data_item_snd (const gchar * src, const gchar * dst,
2921 void *data)
2922 {
2923 return connector_swap_data_item_prefix (src, dst, data, FS_DATA_SND_PREFIX);
2924 }
2925
2926 static gint
2927 connector_open_datum (struct connector *connector, const gchar * path,
2928 guint32 * jid, gint mode, guint32 size)
2929 {
2930 guint32 *data32;
2931 guint32 sizebe;
2932 guint32 chunk_size;
2933 guint8 compression;
2934 GByteArray *rx_msg;
2935 GByteArray *tx_msg;
2936 const guint8 *data;
2937 guint len;
2938 gchar *path_cp1252;
2939 gint res = 0;
2940
2941 if (mode == O_RDONLY)
2942 {
2943 data = DATA_READ_OPEN_REQUEST;
2944 len = sizeof (DATA_READ_OPEN_REQUEST);
2945 }
2946 else if (mode == O_WRONLY)
2947 {
2948 data = DATA_WRITE_OPEN_REQUEST;
2949 len = sizeof (DATA_WRITE_OPEN_REQUEST);
2950 }
2951 else
2952 {
2953 return -EINVAL;
2954 }
2955
2956 tx_msg = connector_new_msg (data, len);
2957 if (!tx_msg)
2958 {
2959 return -ENOMEM;
2960 }
2961
2962 path_cp1252 = connector_get_cp1252 (path);
2963
2964 if (mode == O_RDONLY)
2965 {
2966 g_byte_array_append (tx_msg, (guint8 *) path_cp1252,
2967 strlen (path_cp1252) + 1);
2968 chunk_size = htobe32 (DATA_TRANSF_BLOCK_BYTES);
2969 g_byte_array_append (tx_msg, (guint8 *) & chunk_size, sizeof (guint32));
2970 compression = 1;
2971 g_byte_array_append (tx_msg, &compression, sizeof (guint8));
2972 }
2973
2974 if (mode == O_WRONLY)
2975 {
2976 sizebe = htobe32 (size);
2977 g_byte_array_append (tx_msg, (guint8 *) & sizebe, sizeof (guint32));
2978 g_byte_array_append (tx_msg, (guint8 *) path_cp1252,
2979 strlen (path_cp1252) + 1);
2980 }
2981
2982 rx_msg = connector_tx_and_rx (connector, tx_msg);
2983 if (!rx_msg)
2984 {
2985 res = -EIO;
2986 goto cleanup;
2987 }
2988
2989 if (!connector_get_msg_status (rx_msg))
2990 {
2991 res = -EPERM;
2992 error_print ("%s (%s)\n", snd_strerror (res),
2993 connector_get_msg_string (rx_msg));
2994 free_msg (rx_msg);
2995 goto cleanup;
2996 }
2997
2998 data32 = (guint32 *) & rx_msg->data[6];
2999 *jid = be32toh (*data32);
3000
3001 if (mode == O_RDONLY)
3002 {
3003 data32 = (guint32 *) & rx_msg->data[10];
3004 chunk_size = be32toh (*data32);
3005
3006 compression = rx_msg->data[14];
3007
3008 debug_print (1,
3009 "Open datum info: job id: %d; chunk size: %d; compression: %d\n",
3010 *jid, chunk_size, compression);
3011 }
3012
3013 if (mode == O_WRONLY)
3014 {
3015 debug_print (1, "Open datum info: job id: %d\n", *jid);
3016 }
3017
3018 free_msg (rx_msg);
3019
3020 cleanup:
3021 g_free (path_cp1252);
3022 return res;
3023 }
3024
3025 static gint
3026 connector_close_datum (struct connector *connector,
3027 guint32 jid, gint mode, guint32 wsize)
3028 {
3029 guint32 jidbe;
3030 guint32 wsizebe;
3031 guint32 r_jid;
3032 guint32 asize;
3033 guint32 *data32;
3034 GByteArray *rx_msg;
3035 GByteArray *tx_msg;
3036 const guint8 *data;
3037 guint len;
3038
3039 if (mode == O_RDONLY)
3040 {
3041 data = DATA_READ_CLOSE_REQUEST;
3042 len = sizeof (DATA_READ_CLOSE_REQUEST);
3043 }
3044 else if (mode == O_WRONLY)
3045 {
3046 data = DATA_WRITE_CLOSE_REQUEST;
3047 len = sizeof (DATA_WRITE_CLOSE_REQUEST);
3048 }
3049 else
3050 {
3051 return -EINVAL;
3052 }
3053
3054 tx_msg = connector_new_msg (data, len);
3055 if (!tx_msg)
3056 {
3057 return -ENOMEM;
3058 }
3059
3060 jidbe = htobe32 (jid);
3061 g_byte_array_append (tx_msg, (guchar *) & jidbe, sizeof (guint32));
3062
3063 if (mode == O_WRONLY)
3064 {
3065 wsizebe = htobe32 (wsize);
3066 g_byte_array_append (tx_msg, (guchar *) & wsizebe, sizeof (guint32));
3067 }
3068
3069 rx_msg = connector_tx_and_rx (connector, tx_msg);
3070 if (!rx_msg)
3071 {
3072 return -EIO;
3073 }
3074
3075 if (!connector_get_msg_status (rx_msg))
3076 {
3077 error_print ("%s (%s)\n", snd_strerror (-EPERM),
3078 connector_get_msg_string (rx_msg));
3079 free_msg (rx_msg);
3080 return -EPERM;
3081 }
3082
3083 data32 = (guint32 *) & rx_msg->data[6];
3084 r_jid = be32toh (*data32);
3085
3086 data32 = (guint32 *) & rx_msg->data[10];
3087 asize = be32toh (*data32);
3088
3089 debug_print (1, "Close datum info: job id: %d; size: %d\n", r_jid, asize);
3090
3091 free_msg (rx_msg);
3092
3093 if (mode == O_WRONLY && asize != wsize)
3094 {
3095 error_print
3096 ("Actual download bytes (%d) differs from expected ones (%d)\n",
3097 asize, wsize);
3098 return -EINVAL;
3099 }
3100
3101 return 0;
3102 }
3103
3104 static gint
3105 connector_download_data_prefix (const gchar * path, GByteArray * output,
3106 struct job_control *control, void *data,
3107 const gchar * prefix)
3108 {
3109 gint res;
3110 guint32 seq;
3111 guint32 seqbe;
3112 guint32 jid;
3113 guint32 r_jid;
3114 guint32 r_seq;
3115 guint32 status;
3116 guint8 last;
3117 guint32 hash;
3118 guint32 *data32;
3119 guint32 jidbe;
3120 guint32 data_size;
3121 gboolean active;
3122 GByteArray *rx_msg;
3123 GByteArray *tx_msg;
3124 gchar *path_w_prefix = connector_add_prefix_to_path (path, prefix);
3125 struct connector *connector = data;
3126
3127 res = connector_open_datum (connector, path_w_prefix, &jid, O_RDONLY, 0);
3128 g_free (path_w_prefix);
3129 if (res)
3130 {
3131 return -EIO;
3132 }
3133
3134 usleep (REST_TIME);
3135
3136 jidbe = htobe32 (jid);
3137
3138 res = 0;
3139 seq = 0;
3140 last = 0;
3141 control->data = NULL;
3142 if (control)
3143 {
3144 g_mutex_lock (&control->mutex);
3145 active = control->active;
3146 g_mutex_unlock (&control->mutex);
3147 }
3148 else
3149 {
3150 active = TRUE;
3151 }
3152 while (!last && active)
3153 {
3154 tx_msg =
3155 connector_new_msg (DATA_READ_PARTIAL_REQUEST,
3156 sizeof (DATA_READ_PARTIAL_REQUEST));
3157 g_byte_array_append (tx_msg, (guint8 *) & jidbe, sizeof (guint32));
3158 seqbe = htobe32 (seq);
3159 g_byte_array_append (tx_msg, (guint8 *) & seqbe, sizeof (guint32));
3160 rx_msg = connector_tx_and_rx (connector, tx_msg);
3161 if (!rx_msg)
3162 {
3163 res = -EIO;
3164 break;
3165 }
3166
3167 if (!connector_get_msg_status (rx_msg))
3168 {
3169 res = -EPERM;
3170 error_print ("%s (%s)\n", snd_strerror (res),
3171 connector_get_msg_string (rx_msg));
3172 free_msg (rx_msg);
3173 break;
3174 }
3175
3176 data32 = (guint32 *) & rx_msg->data[6];
3177 r_jid = be32toh (*data32);
3178
3179 data32 = (guint32 *) & rx_msg->data[10];
3180 r_seq = be32toh (*data32);
3181
3182 data32 = (guint32 *) & rx_msg->data[14];
3183 status = be32toh (*data32);
3184
3185 last = rx_msg->data[18];
3186
3187 data32 = (guint32 *) & rx_msg->data[19];
3188 hash = be32toh (*data32);
3189
3190 data32 = (guint32 *) & rx_msg->data[23];
3191 data_size = be32toh (*data32);
3192
3193 if (data_size)
3194 {
3195 debug_print (1,
3196 "Read datum info: job id: %d; last: %d; seq: %d; status: %d; hash: 0x%08x\n",
3197 r_jid, last, r_seq, status, hash);
3198
3199 g_byte_array_append (output, (guint8 *) & rx_msg->data[27],
3200 data_size);
3201 }
3202 else
3203 {
3204 // Sometimes, the first message returns 0 data size and the rest of the parameters are not initialized.
3205 debug_print (1,
3206 "Read datum info: job id: %d; last: %d, hash: 0x%08x\n",
3207 r_jid, last, hash);
3208 status = 0;
3209 }
3210
3211 free_msg (rx_msg);
3212 seq++;
3213
3214 if (control)
3215 {
3216 set_job_control_progress (control, status / 1000.0);
3217 g_mutex_lock (&control->mutex);
3218 active = control->active;
3219 g_mutex_unlock (&control->mutex);
3220 }
3221
3222 usleep (REST_TIME);
3223 }
3224
3225 return connector_close_datum (connector, jid, O_RDONLY, 0);
3226 }
3227
3228 static gint
3229 connector_download_data_any (const gchar * path, GByteArray * output,
3230 struct job_control *control, void *data)
3231 {
3232 control->parts = 1;
3233 control->part = 0;
3234 return connector_download_data_prefix (path, output, control, data, NULL);
3235 }
3236
3237 static gint
3238 connector_download_data_prj (const gchar * path, GByteArray * output,
3239 struct job_control *control, void *data)
3240 {
3241 return connector_download_data_prefix (path, output, control, data,
3242 FS_DATA_PRJ_PREFIX);
3243 }
3244
3245 static gint
3246 connector_download_data_snd (const gchar * path, GByteArray * output,
3247 struct job_control *control, void *data)
3248 {
3249 return connector_download_data_prefix (path, output, control, data,
3250 FS_DATA_SND_PREFIX);
3251 }
3252
3253 gchar *
3254 connector_get_sample_path_from_hash_size (struct connector *connector,
3255 guint32 hash, guint32 size)
3256 {
3257 guint32 aux32;
3258 gchar *path;
3259 GByteArray *rx_msg, *tx_msg =
3260 connector_new_msg (FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST,
3261 sizeof
3262 (FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST));
3263
3264 aux32 = htobe32 (hash);
3265 memcpy (&tx_msg->data[5], &aux32, sizeof (guint32));
3266 aux32 = htobe32 (size);
3267 memcpy (&tx_msg->data[9], &aux32, sizeof (guint32));
3268
3269 rx_msg = connector_tx_and_rx (connector, tx_msg);
3270 if (!rx_msg)
3271 {
3272 return NULL;
3273 }
3274
3275 if (connector_get_msg_status (rx_msg))
3276 {
3277 path = strdup ((gchar *) & rx_msg->data[14]);
3278 }
3279 else
3280 {
3281 path = NULL;
3282 }
3283 g_byte_array_free (rx_msg, TRUE);
3284 return path;
3285 }
3286
3287 static gint
3288 connector_download_pkg (const gchar * path, GByteArray * output,
3289 struct job_control *control, void *data,
3290 enum package_type type,
3291 const struct fs_operations *ops,
3292 fs_remote_file_op download)
3293 {
3294 gint ret;
3295 gchar *pkg_name;
3296 struct package pkg;
3297 struct connector *connector = data;
3298
3299 pkg_name = connector_get_download_name (connector, NULL, ops, path);
3300 if (!pkg_name)
3301 {
3302 return -1;
3303 }
3304
3305 if (package_begin
3306 (&pkg, pkg_name, connector->fw_version, &connector->device_desc, type))
3307 {
3308 g_free (pkg_name);
3309 return -1;
3310 }
3311
3312 ret =
3313 package_receive_pkg_resources (&pkg, path, control, connector, download,
3314 connector_download_sample_part);
3315 ret = ret || package_end (&pkg, output);
3316
3317 package_destroy (&pkg);
3318 return ret;
3319 }
3320
3321 static gint
3322 connector_download_data_snd_pkg (const gchar * path, GByteArray * output,
3323 struct job_control *control, void *data)
3324 {
3325 return connector_download_pkg (path, output, control, data,
3326 PKG_FILE_TYPE_SOUND,
3327 &FS_DATA_SND_OPERATIONS,
3328 connector_download_data_snd);
3329 }
3330
3331 static gint
3332 connector_download_data_prj_pkg (const gchar * path, GByteArray * output,
3333 struct job_control *control, void *data)
3334 {
3335 return connector_download_pkg (path, output, control, data,
3336 PKG_FILE_TYPE_PROJECT,
3337 &FS_DATA_PRJ_OPERATIONS,
3338 connector_download_data_prj);
3339 }
3340
3341 static gint
3342 connector_download_raw_pst_pkg (const gchar * path, GByteArray * output,
3343 struct job_control *control, void *data)
3344 {
3345 return connector_download_pkg (path, output, control, data,
3346 PKG_FILE_TYPE_PRESET,
3347 &FS_RAW_ANY_OPERATIONS,
3348 connector_download_raw);
3349 }
3350
3351 gchar *
3352 connector_get_upload_path (struct connector *connector,
3353 struct item_iterator *remote_iter,
3354 const struct fs_operations *ops,
3355 const gchar * dst_dir, const gchar * src_path,
3356 gint32 * next_index)
3357 {
3358 gchar *path, *indexs, *namec, *name, *aux;
3359 gboolean new;
3360
3361 if (ops->fs == FS_SAMPLES || ops->fs == FS_RAW_ALL
3362 || ops->fs == FS_RAW_PRESETS)
3363 {
3364 namec = strdup (src_path);
3365 name = basename (namec);
3366 remove_ext (name);
3367 aux = chain_path (dst_dir, name);
3368 g_free (namec);
3369
3370 if (ops->fs == FS_RAW_ALL || ops->fs == FS_RAW_PRESETS)
3371 {
3372 path = connector_add_ext_to_mc_snd (aux);
3373 g_free (aux);
3374 }
3375 else
3376 {
3377 path = aux;
3378 }
3379 return path;
3380 }
3381
3382 new = FALSE;
3383 if (!remote_iter)
3384 {
3385 new = TRUE;
3386 remote_iter = malloc (sizeof (struct item_iterator));
3387 if (ops->readdir (remote_iter, dst_dir, connector))
3388 {
3389 return strdup (dst_dir);
3390 }
3391 }
3392
3393 if (remote_iter->item.index == *next_index)
3394 {
3395 (*next_index)++;
3396 }
3397 else
3398 {
3399 while (!next_item_iterator (remote_iter))
3400 {
3401 if (remote_iter->item.index > *next_index)
3402 {
3403 break;
3404 }
3405 (*next_index)++;
3406 }
3407 }
3408
3409 if (new)
3410 {
3411 free_item_iterator (remote_iter);
3412 }
3413
3414 indexs = malloc (PATH_MAX);
3415 snprintf (indexs, PATH_MAX, "%d", *next_index);
3416 path = chain_path (dst_dir, indexs);
3417 g_free (indexs);
3418
3419 (*next_index)++;
3420
3421 return path;
3422 }
3423
3424 gchar *
3425 connector_get_download_name (struct connector *connector,
3426 struct item_iterator *remote_iter,
3427 const struct fs_operations *ops,
3428 const gchar * src_path)
3429 {
3430 gint32 id;
3431 const gchar *src_dir;
3432 gchar *namec, *name, *src_dirc;
3433 gint ret;
3434 gboolean new = FALSE;
3435
3436 namec = strdup (src_path);
3437 name = basename (namec);
3438
3439 if (ops->fs == FS_SAMPLES || ops->fs == FS_RAW_ALL
3440 || ops->fs == FS_RAW_PRESETS)
3441 {
3442 name = strdup (name);
3443 goto end;
3444 }
3445
3446 if (!remote_iter)
3447 {
3448 new = TRUE;
3449 remote_iter = malloc (sizeof (struct item_iterator));
3450 src_dirc = strdup (src_path);
3451 src_dir = dirname (src_dirc);
3452 ret = ops->readdir (remote_iter, src_dir, connector);
3453 g_free (src_dirc);
3454 if (ret)
3455 {
3456 name = NULL;
3457 goto cleanup;
3458 }
3459 }
3460
3461 id = atoi (name);
3462 name = NULL;
3463
3464 while (!next_item_iterator (remote_iter))
3465 {
3466 if (remote_iter->item.index == id)
3467 {
3468 name = get_item_name (&remote_iter->item);
3469 break;
3470 }
3471 }
3472
3473 cleanup:
3474 if (new)
3475 {
3476 free_item_iterator (remote_iter);
3477 }
3478 g_free (namec);
3479 end:
3480 return name;
3481 }
3482
3483 gchar *
3484 connector_get_download_path (struct connector *connector,
3485 struct item_iterator *remote_iter,
3486 const struct fs_operations *ops,
3487 const gchar * dst_dir, const gchar * src_path)
3488 {
3489 gchar *path, *src_pathc, *name, *dl_ext, *filename;
3490 const gchar *src_fpath, *md_ext, *ext = get_ext (src_path);
3491
3492 src_pathc = strdup (src_path);
3493 if (ext && strcmp (ext, "metadata") == 0 && ops->fs != FS_SAMPLES)
3494 {
3495 src_fpath = dirname (src_pathc);
3496 md_ext = ".metadata";
3497 }
3498 else
3499 {
3500 src_fpath = src_pathc;
3501 md_ext = "";
3502 }
3503
3504 name = connector_get_download_name (connector, remote_iter, ops, src_fpath);
3505 if (name)
3506 {
3507 dl_ext = connector_get_full_ext (&connector->device_desc, ops);
3508 filename = malloc (PATH_MAX);
3509 snprintf (filename, PATH_MAX, "%s.%s%s", name, dl_ext, md_ext);
3510 path = chain_path (dst_dir, filename);
3511 g_free (name);
3512 g_free (dl_ext);
3513 g_free (filename);
3514 }
3515 else
3516 {
3517 path = NULL;
3518 }
3519
3520 g_free (src_pathc);
3521 return path;
3522 }
3523
3524 static gint
3525 connector_upload_data_prefix (const gchar * path, GByteArray * array,
3526 struct job_control *control, void *data,
3527 const gchar * prefix)
3528 {
3529 gint res;
3530 guint32 seq;
3531 guint32 jid;
3532 guint32 crc;
3533 guint32 len;
3534 guint32 r_jid;
3535 guint32 r_seq;
3536 guint32 offset;
3537 guint32 *data32;
3538 guint32 jidbe;
3539 guint32 aux32;
3540 gboolean active;
3541 guint32 total;
3542 GByteArray *rx_msg;
3543 GByteArray *tx_msg;
3544 gchar *path_w_prefix = connector_add_prefix_to_path (path, prefix);
3545 struct connector *connector = data;
3546
3547 res =
3548 connector_open_datum (connector, path_w_prefix, &jid, O_WRONLY,
3549 array->len);
3550 g_free (path_w_prefix);
3551 if (res)
3552 {
3553 goto end;
3554 }
3555
3556 usleep (REST_TIME);
3557
3558 jidbe = htobe32 (jid);
3559
3560 seq = 0;
3561 offset = 0;
3562 control->data = NULL;
3563 if (control)
3564 {
3565 g_mutex_lock (&control->mutex);
3566 active = control->active;
3567 g_mutex_unlock (&control->mutex);
3568 }
3569 else
3570 {
3571 active = TRUE;
3572 }
3573
3574 while (offset < array->len && active)
3575 {
3576 tx_msg =
3577 connector_new_msg (DATA_WRITE_PARTIAL_REQUEST,
3578 sizeof (DATA_WRITE_PARTIAL_REQUEST));
3579 g_byte_array_append (tx_msg, (guint8 *) & jidbe, sizeof (guint32));
3580 aux32 = htobe32 (seq);
3581 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3582
3583 if (offset + DATA_TRANSF_BLOCK_BYTES < array->len)
3584 {
3585 len = DATA_TRANSF_BLOCK_BYTES;
3586 }
3587 else
3588 {
3589 len = array->len - offset;
3590 }
3591
3592 crc = crc32 (0xffffffff, &array->data[offset], len);
3593 aux32 = htobe32 (crc);
3594 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3595
3596 aux32 = htobe32 (len);
3597 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3598
3599 g_byte_array_append (tx_msg, &array->data[offset], len);
3600
3601 rx_msg = connector_tx_and_rx (connector, tx_msg);
3602 if (!rx_msg)
3603 {
3604 res = -EIO;
3605 goto end;
3606 }
3607
3608 usleep (REST_TIME);
3609
3610 if (!connector_get_msg_status (rx_msg))
3611 {
3612 res = -EPERM;
3613 error_print ("%s (%s)\n", snd_strerror (res),
3614 connector_get_msg_string (rx_msg));
3615 free_msg (rx_msg);
3616 break;
3617 }
3618
3619 data32 = (guint32 *) & rx_msg->data[6];
3620 r_jid = be32toh (*data32);
3621
3622 data32 = (guint32 *) & rx_msg->data[10];
3623 r_seq = be32toh (*data32);
3624
3625 data32 = (guint32 *) & rx_msg->data[14];
3626 total = be32toh (*data32);
3627
3628 free_msg (rx_msg);
3629
3630 debug_print (1,
3631 "Write datum info: job id: %d; seq: %d; total: %d\n",
3632 r_jid, r_seq, total);
3633
3634 seq++;
3635 offset += len;
3636
3637 if (total != offset)
3638 {
3639 error_print
3640 ("Actual upload bytes (%d) differs from expected ones (%d)\n",
3641 total, offset);
3642 }
3643
3644 if (control)
3645 {
3646 set_job_control_progress (control, offset / (gdouble) array->len);
3647 g_mutex_lock (&control->mutex);
3648 active = control->active;
3649 g_mutex_unlock (&control->mutex);
3650 }
3651 }
3652
3653 debug_print (2, "%d bytes sent\n", offset);
3654
3655 res = connector_close_datum (connector, jid, O_WRONLY, array->len);
3656
3657 end:
3658 return res;
3659 }
3660
3661 static gint
3662 connector_upload_data_any (const gchar * path, GByteArray * array,
3663 struct job_control *control, void *data)
3664 {
3665 control->parts = 1;
3666 control->part = 0;
3667 return connector_upload_data_prefix (path, array, control, data, NULL);
3668 }
3669
3670 static gint
3671 connector_upload_data_prj (const gchar * path, GByteArray * array,
3672 struct job_control *control, void *data)
3673 {
3674 return connector_upload_data_prefix (path, array, control, data,
3675 FS_DATA_PRJ_PREFIX);
3676 }
3677
3678 static gint
3679 connector_upload_data_snd (const gchar * path, GByteArray * array,
3680 struct job_control *control, void *data)
3681 {
3682 return connector_upload_data_prefix (path, array, control, data,
3683 FS_DATA_SND_PREFIX);
3684 }
3685
3686 static gint
3687 connector_upload_pkg (const gchar * path, GByteArray * input,
3688 struct job_control *control, void *data,
3689 guint8 type, const struct fs_operations *ops,
3690 fs_remote_file_op upload)
3691 {
3692 gint ret;
3693 struct package pkg;
3694 struct connector *connector = data;
3695
3696 ret = package_open (&pkg, input, &connector->device_desc);
3697 if (!ret)
3698 {
3699 ret = package_send_pkg_resources (&pkg, path, control, connector,
3700 upload, connector_upload_sample_part);
3701 package_close (&pkg);
3702 }
3703 return ret;
3704 }
3705
3706 static gint
3707 connector_upload_data_snd_pkg (const gchar * path, GByteArray * input,
3708 struct job_control *control, void *data)
3709 {
3710 return connector_upload_pkg (path, input, control, data,
3711 PKG_FILE_TYPE_SOUND,
3712 &FS_DATA_SND_OPERATIONS,
3713 connector_upload_data_snd);
3714 }
3715
3716 static gint
3717 connector_upload_data_prj_pkg (const gchar * path, GByteArray * input,
3718 struct job_control *control, void *data)
3719 {
3720 return connector_upload_pkg (path, input, control, data,
3721 PKG_FILE_TYPE_PROJECT,
3722 &FS_DATA_PRJ_OPERATIONS,
3723 connector_upload_data_prj);
3724 }
3725
3726 static gint
3727 connector_upload_raw_pst_pkg (const gchar * path, GByteArray * input,
3728 struct job_control *control, void *data)
3729 {
3730 return connector_upload_pkg (path, input, control, data,
3731 PKG_FILE_TYPE_PRESET,
3732 &FS_RAW_ANY_OPERATIONS, connector_upload_raw);
3733 }
3734
3735 gchar *
3736 connector_get_full_ext (const struct connector_device_desc *desc,
3737 const struct fs_operations *ops)
3738 {
3739 gchar *ext = malloc (LABEL_MAX);
3740 if (ops->fs == FS_SAMPLES)
3741 {
3742 snprintf (ext, LABEL_MAX, "%s", ops->extension);
3743 }
3744 else
3745 {
3746 snprintf (ext, LABEL_MAX, "%s%s", desc->alias, ops->extension);
3747 }
3748 return ext;
3749 }
3750
3751 void
3752 connector_enable_dir_cache (struct connector *connector)
3753 {
3754 g_mutex_lock (&connector->mutex);
3755 connector->dir_cache =
3756 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_msg);
3757 g_mutex_unlock (&connector->mutex);
3758 }
3759
3760 void
3761 connector_disable_dir_cache (struct connector *connector)
3762 {
3763 g_mutex_lock (&connector->mutex);
3764 g_hash_table_destroy (connector->dir_cache);
3765 connector->dir_cache = NULL;
3766 g_mutex_unlock (&connector->mutex);
3767 }
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #include <glib.h>
21 #include <alsa/asoundlib.h>
2220 #include "utils.h"
2321
2422 #ifndef CONNECTOR_H
2523 #define CONNECTOR_H
2624
27 #define SYSEX_TIMEOUT 5000
28 #define REST_TIME 50000
29
30 struct connector
31 {
32 struct connector_device_desc device_desc;
33 snd_rawmidi_t *inputp;
34 snd_rawmidi_t *outputp;
35 gchar *device_name;
36 gchar *overbridge_name;
37 gchar *fw_version;
38 gushort seq;
39 GMutex mutex;
40 ssize_t rx_len;
41 guint8 *buffer;
42 gint npfds;
43 struct pollfd *pfds;
44 GHashTable *dir_cache;
45 };
46
47 enum connector_fs
48 {
49 FS_SAMPLES = 0x1,
50 FS_RAW_ALL = 0x2,
51 FS_RAW_PRESETS = 0x4,
52 FS_DATA_ALL = 0x8,
53 FS_DATA_PRJ = 0x10,
54 FS_DATA_SND = 0x20,
55 };
56
57 struct connector_iterator_data
58 {
59 GByteArray *msg;
60 guint32 pos;
61 guint32 hash;
62 guint16 operations;
63 guint8 has_valid_data;
64 guint8 has_metadata;
65 enum connector_fs fs;
66 gboolean cached;
67 };
68
69 struct connector_system_device
70 {
71 gchar *name;
72 guint card;
73 };
74
75 enum connector_sysex_transfer_status
76 {
77 WAITING,
78 SENDING,
79 RECEIVING,
80 FINISHED
81 };
82
83 struct connector_sysex_transfer
84 {
85 gboolean active;
86 enum connector_sysex_transfer_status status;
87 gint timeout; //Measured in ms. -1 is infinite.
88 gboolean batch;
89 GMutex mutex;
90 GByteArray *raw;
91 };
92
93 enum connector_storage
94 {
95 STORAGE_PLUS_DRIVE = 0x1,
96 STORAGE_RAM = 0x2
97 };
98
99 struct connector_storage_stats
100 {
101 const gchar *name;
102 guint64 bsize;
103 guint64 bfree;
104 };
105
106 const struct fs_operations *connector_get_fs_operations (enum connector_fs);
107
108 gint connector_init (struct connector *, gint, const char *);
109
110 void connector_destroy (struct connector *);
111
112 gboolean connector_check (struct connector *);
113
114 GArray *connector_get_system_devices ();
115
116 gint connector_tx_sysex (struct connector *,
117 struct connector_sysex_transfer *);
118
119 gint connector_rx_sysex (struct connector *,
120 struct connector_sysex_transfer *);
121
122 void connector_rx_drain (struct connector *);
123
124 gint connector_upgrade_os (struct connector *,
125 struct connector_sysex_transfer *);
126
127 gint connector_get_storage_stats (struct connector *,
128 enum connector_storage,
129 struct connector_storage_stats *);
130
131 gdouble connector_get_storage_stats_percent (struct connector_storage_stats
132 *);
133
134 gchar *connector_get_upload_path (struct connector *, struct item_iterator *,
135 const struct fs_operations *, const gchar *,
136 const gchar *, gint32 *);
137
138 gchar *connector_get_download_name (struct connector *,
139 struct item_iterator *,
140 const struct fs_operations *,
141 const gchar *);
142
143 gchar *connector_get_download_path (struct connector *,
144 struct item_iterator *,
145 const struct fs_operations *,
146 const gchar *, const gchar *);
147
148
149 gchar *connector_get_full_ext (const struct connector_device_desc *,
150 const struct fs_operations *);
151
152 gchar *connector_get_sample_path_from_hash_size (struct connector *,
153 guint32, guint32);
154
155 void connector_enable_dir_cache (struct connector *);
156
157 void connector_disable_dir_cache (struct connector *);
25 gint connector_init (struct backend *backend, const gchar * midi_id,
26 const gchar * name,
27 struct sysex_transfer *sysex_transfer);
15828
15929 #endif
0 /*
1 * common.h
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "common.h"
21
22 gchar *
23 common_slot_get_upload_path (struct backend *backend,
24 struct item_iterator *remote_iter,
25 const struct fs_operations *ops,
26 const gchar * dst_dir, const gchar * src_path,
27 gint32 * next_index)
28 {
29 //In SLOT mode, dst_dir includes the index, ':' and the item name.
30 return strdup (dst_dir);
31 }
32
33 int
34 common_slot_get_id_name_from_path (const char *path, guint * id,
35 gchar ** name)
36 {
37 gint err = 0;
38 gchar *path_copy, *index_name, *remainder;
39
40 path_copy = strdup (path);
41 index_name = basename (path_copy);
42 *id = (gint) strtol (index_name, &remainder, 10);
43 if (strncmp (remainder, BE_SAMPLE_ID_NAME_SEPARATOR,
44 strlen (BE_SAMPLE_ID_NAME_SEPARATOR)) == 0)
45 {
46 remainder++; //Skip ':'
47 }
48 else
49 {
50 if (name)
51 {
52 error_print ("Path name not provided properly\n");
53 err = -EINVAL;
54 goto end;
55 }
56 }
57
58 if (name)
59 {
60 if (*remainder)
61 {
62 *name = strdup (remainder);
63 }
64 else
65 {
66 *name = NULL;
67 }
68 }
69
70 end:
71 g_free (path_copy);
72 return err;
73 }
0 /*
1 * common.c
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "backend.h"
21
22 gchar *common_slot_get_upload_path (struct backend *backend,
23 struct item_iterator *remote_iter,
24 const struct fs_operations *ops,
25 const gchar * dst_dir,
26 const gchar * src_path,
27 gint32 * next_index);
28
29 int common_slot_get_id_name_from_path (const char *path, guint * id,
30 gchar ** name);
0 /*
1 * cz.c
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <libgen.h>
21 #include "cz.h"
22 #include "common.h"
23
24 #define CZ_PROGRAM_LEN 263
25 #define CZ_PROGRAM_LEN_FIXED 264
26 #define CZ_MAX_PROGRAMS 16
27 #define CZ_PRESET_PREFIX "CZ-101"
28 #define CZ_PROGRAM_HEADER_ID 6
29 #define CZ_PROGRAM_HEADER_OFFSET 6
30 #define CZ_MEM_TYPE_OFFSET 0x20
31 #define CZ_PANEL_ID 0x60
32 #define CZ_FIRST_CARTRIDGE_ID 0x40
33 #define CZ_PANEL_PATH "/panel"
34
35 static const char *CZ_MEM_TYPES[] =
36 { "preset", "internal", "cartridge", NULL };
37
38 static const guint8 CZ_PROGRAM_REQUEST[] =
39 { 0xf0, 0x44, 0x00, 0x00, 0x70, 0x10, 0x00, 0x70, 0x31, 0xf7 };
40
41 static const guint8 CZ_PROGRAM_HEADER[] =
42 { 0xf0, 0x44, 0x00, 0x00, 0x70, 0x20, 0x00 };
43
44 enum cz_fs
45 {
46 FS_PROGRAM_CZ = 1
47 };
48
49 struct cz_type_iterator_data
50 {
51 guint next;
52 gint type;
53 struct backend *backend;
54 };
55
56 static gchar *
57 cz_get_download_path (struct backend *backend,
58 struct item_iterator *remote_iter,
59 const struct fs_operations *ops, const gchar * dst_dir,
60 const gchar * src_path)
61 {
62 gchar *name = malloc (PATH_MAX);
63 if (strcmp (&src_path[1], "panel"))
64 {
65 gchar *src_path_copy = strdup (src_path);
66 gchar *src_dir_copy = strdup (src_path);
67 gchar *filename = basename (src_path_copy);
68 gchar *dir = dirname (src_dir_copy);
69 gint index = atoi (filename);
70 snprintf (name, PATH_MAX, "%s/%s %s %02d.syx", dst_dir,
71 CZ_PRESET_PREFIX, &dir[1], index);
72 g_free (src_path_copy);
73 g_free (src_dir_copy);
74 }
75 else
76 {
77 snprintf (name, PATH_MAX, "%s/%s panel.syx", dst_dir, CZ_PRESET_PREFIX);
78 }
79 return name;
80 }
81
82 static GByteArray *
83 cz_get_program_dump_msg (guint8 id)
84 {
85 GByteArray *tx_msg = g_byte_array_sized_new (sizeof (CZ_PROGRAM_REQUEST));
86 g_byte_array_append (tx_msg, CZ_PROGRAM_REQUEST,
87 sizeof (CZ_PROGRAM_REQUEST));
88 tx_msg->data[CZ_PROGRAM_HEADER_OFFSET] = id;
89 return tx_msg;
90 }
91
92 static guint
93 cz_next_dentry_root (struct item_iterator *iter)
94 {
95 GByteArray *tx_msg, *rx_msg;
96 struct cz_type_iterator_data *data = iter->data;
97
98 if (data->next < 3)
99 {
100 iter->item.id = 0x1000 + data->next; //Unique id
101 snprintf (iter->item.name, LABEL_MAX, "%s", CZ_MEM_TYPES[data->next]);
102 iter->item.type = ELEKTROID_DIR;
103 iter->item.size = -1;
104
105 if (data->next == 2)
106 {
107 tx_msg = cz_get_program_dump_msg (CZ_FIRST_CARTRIDGE_ID);
108 rx_msg = backend_tx_and_rx_sysex (data->backend, tx_msg,
109 BE_SYSEX_TIMEOUT_GUESS_MS);
110 data->next++;
111 if (rx_msg)
112 {
113 free_msg (rx_msg);
114 return 0;
115 }
116 }
117 else
118 {
119 data->next++;
120 return 0;
121 }
122 }
123
124 if (data->next == 3)
125 {
126 iter->item.id = CZ_PANEL_ID;
127 snprintf (iter->item.name, LABEL_MAX, "panel");
128 iter->item.type = ELEKTROID_FILE;
129 iter->item.size = CZ_PROGRAM_LEN_FIXED;
130 data->next++;
131 return 0;
132 }
133 else
134 {
135 return -ENOENT;
136 }
137 }
138
139 static guint
140 cz_next_dentry (struct item_iterator *iter)
141 {
142 struct cz_type_iterator_data *data = iter->data;
143
144 if (data->next >= CZ_MAX_PROGRAMS)
145 {
146 return -ENOENT;
147 }
148
149 iter->item.id = data->next + data->type * CZ_MEM_TYPE_OFFSET;
150 snprintf (iter->item.name, LABEL_MAX, "%d", data->next + 1);
151 iter->item.type = ELEKTROID_FILE;
152 iter->item.size = CZ_PROGRAM_LEN_FIXED;
153 data->next++;
154
155 return 0;
156 }
157
158 static gint
159 cz_copy_iterator (struct item_iterator *dst, struct item_iterator *src,
160 gboolean cached)
161 {
162 struct cz_type_iterator_data *data = src->data;
163 struct cz_type_iterator_data *ndata =
164 g_malloc (sizeof (struct cz_type_iterator_data));
165 ndata->next = 0;
166 ndata->type = data->type;
167 ndata->backend = data->backend;
168 dst->data = ndata;
169 dst->next = cz_next_dentry_root;
170 dst->free = g_free;
171 dst->copy = cz_copy_iterator;
172
173 return 0;
174 }
175
176 static gint
177 get_mem_type (const gchar * name)
178 {
179 const char **mem_type = CZ_MEM_TYPES;
180 for (int i = 0; *mem_type; i++, mem_type++)
181 {
182 if (!strcmp (*mem_type, name))
183 {
184 return i;
185 }
186 }
187 return -1;
188 }
189
190 static gint
191 cz_read_dir (struct backend *backend, struct item_iterator *iter,
192 const gchar * path)
193 {
194 gint mem_type;
195
196 if (!strcmp (path, "/"))
197 {
198 struct cz_type_iterator_data *data =
199 g_malloc (sizeof (struct cz_type_iterator_data));
200 data->next = 0;
201 data->type = -1;
202 data->backend = backend;
203 iter->data = data;
204 iter->next = cz_next_dentry_root;
205 iter->copy = cz_copy_iterator;
206 iter->free = g_free;
207 return 0;
208 }
209 else if ((mem_type = get_mem_type (&path[1])) >= 0)
210 {
211 struct cz_type_iterator_data *data =
212 g_malloc (sizeof (struct cz_type_iterator_data));
213 data->next = 0;
214 data->type = mem_type;
215 data->backend = backend;
216 iter->data = data;
217 iter->next = cz_next_dentry;
218 iter->copy = cz_copy_iterator;
219 iter->free = g_free;
220 return 0;
221 }
222 else
223 {
224 return -ENOTDIR;
225 }
226 }
227
228 static gint
229 cz_download (struct backend *backend, const gchar * path,
230 GByteArray * output, struct job_control *control)
231 {
232 guint8 id;
233 gboolean active;
234 gint len, type, err = 0;
235 GByteArray *tx_msg, *rx_msg;
236 gchar *dirname_copy, *dir, *basename_copy;
237
238 control->parts = 1;
239 control->part = 0;
240 set_job_control_progress (control, 0.0);
241
242 if (strcmp (path, CZ_PANEL_PATH))
243 {
244 dirname_copy = strdup (path);
245 dir = dirname (dirname_copy);
246 type = get_mem_type (&dir[1]);
247 g_free (dirname_copy);
248 if (type < 0)
249 {
250 err = -EINVAL;
251 goto end;
252 }
253
254 basename_copy = strdup (path);
255 id = atoi (basename (basename_copy)) - 1 + type * CZ_MEM_TYPE_OFFSET;
256 g_free (basename_copy);
257 }
258 else
259 {
260 id = CZ_PANEL_ID;
261 }
262
263 tx_msg = cz_get_program_dump_msg (id);
264 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1);
265 if (!rx_msg)
266 {
267 return -EIO;
268 }
269 len = rx_msg->len;
270 if (len != CZ_PROGRAM_LEN)
271 {
272 err = -EINVAL;
273 goto cleanup;
274 }
275
276 g_byte_array_append (output, CZ_PROGRAM_HEADER, sizeof (CZ_PROGRAM_HEADER));
277 g_byte_array_append (output, &rx_msg->data[CZ_PROGRAM_HEADER_OFFSET],
278 CZ_PROGRAM_LEN - CZ_PROGRAM_HEADER_OFFSET);
279 output->data[CZ_PROGRAM_HEADER_ID] = id;
280
281 g_mutex_lock (&control->mutex);
282 active = control->active;
283 g_mutex_unlock (&control->mutex);
284
285 if (active)
286 {
287 set_job_control_progress (control, 1.0);
288 }
289 else
290 {
291 err = -ECANCELED;
292 }
293
294 cleanup:
295 free_msg (rx_msg);
296 end:
297 return err;
298 }
299
300 static gint
301 cz_upload (struct backend *backend, const gchar * path, GByteArray * input,
302 struct job_control *control)
303 {
304 guint8 id;
305 gboolean active;
306 struct sysex_transfer transfer;
307 char *name_copy, *dir_copy, *dir;
308 gint mem_type, err = 0;
309
310 dir_copy = strdup (path);
311 dir = dirname (dir_copy);
312 mem_type = get_mem_type (&dir[1]);
313 if (mem_type >= 0)
314 {
315 name_copy = strdup (path);
316 id = atoi (basename (name_copy)) - 1 + mem_type * CZ_MEM_TYPE_OFFSET;
317 g_free (name_copy);
318 }
319 else
320 {
321 if (strncmp (path, CZ_PANEL_PATH, strlen (CZ_PANEL_PATH)))
322 {
323 err = -EIO;
324 goto cleanup;
325 }
326 else
327 {
328 id = CZ_PANEL_ID;
329 }
330 }
331
332 g_mutex_lock (&backend->mutex);
333
334 control->parts = 1;
335 control->part = 0;
336 set_job_control_progress (control, 0.0);
337
338 transfer.raw = g_byte_array_sized_new (input->len);
339 g_byte_array_append (transfer.raw, input->data, input->len);
340 transfer.raw->data[CZ_PROGRAM_HEADER_ID] = id;
341
342 err = backend_tx_sysex (backend, &transfer);
343 free_msg (transfer.raw);
344 if (err < 0)
345 {
346 goto cleanup;
347 }
348
349 g_mutex_lock (&control->mutex);
350 active = control->active;
351 g_mutex_unlock (&control->mutex);
352 if (active)
353 {
354 set_job_control_progress (control, 1.0);
355 }
356 else
357 {
358 err = -ECANCELED;
359 }
360
361 cleanup:
362 g_mutex_unlock (&backend->mutex);
363 g_free (dir_copy);
364 return err;
365 }
366
367 static void
368 cz_print (struct item_iterator *iter, struct backend *backend)
369 {
370 printf ("%c % 4" PRId64 "B %s\n", iter->item.type, iter->item.size,
371 iter->item.name);
372 }
373
374 //As program X in preset storage and program X in internal staorage have different IDs
375 //it won't work with the id as the filename so the item name must be used.
376
377 static const struct fs_operations FS_PROGRAM_CZ_OPERATIONS = {
378 .fs = FS_PROGRAM_CZ,
379 .options = FS_OPTION_SINGLE_OP | FS_OPTION_SLOT_STORAGE |
380 FS_OPTION_SORT_BY_ID | FS_OPTION_SHOW_SIZE_COLUMN,
381 .name = "program",
382 .gui_name = "Programs",
383 .gui_icon = BE_FILE_ICON_SND,
384 .readdir = cz_read_dir,
385 .print_item = cz_print,
386 .download = cz_download,
387 .upload = cz_upload,
388 .load = load_file,
389 .save = save_file,
390 .get_ext = backend_get_fs_ext,
391 .get_upload_path = common_slot_get_upload_path,
392 .get_download_path = cz_get_download_path,
393 .type_ext = "syx"
394 };
395
396 static const struct fs_operations *FS_CZ_OPERATIONS[] = {
397 &FS_PROGRAM_CZ_OPERATIONS, NULL
398 };
399
400 gint
401 cz_handshake (struct backend *backend)
402 {
403 gint len, err = 0;
404 GByteArray *tx_msg, *rx_msg;
405
406 tx_msg = cz_get_program_dump_msg (CZ_PANEL_ID);
407 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg,
408 BE_SYSEX_TIMEOUT_GUESS_MS);
409 if (!rx_msg)
410 {
411 return -ENODEV;
412 }
413 len = rx_msg->len;
414 if (len != CZ_PROGRAM_LEN)
415 {
416 err = -ENODEV;
417 goto end;
418 }
419
420 backend->device_desc.filesystems = FS_PROGRAM_CZ;
421 backend->fs_ops = FS_CZ_OPERATIONS;
422 snprintf (backend->device_name, LABEL_MAX, "Casio CZ-101");
423
424 end:
425 free_msg (rx_msg);
426 return err;
427 }
0 /*
1 * cz.h
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef CZ_H
21 #define CZ_H
22
23 #include "backend.h"
24
25 gint cz_handshake (struct backend *);
26
27 #endif
0 /*
1 * efactor.c
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "efactor.h"
21 #include "common.h"
22
23 #define EFACTOR_MSG_TYPE_OBJECT 0x31
24 #define EFACTOR_MSG_TYPE_VALUE 0x3b
25
26 #define EFACTOR_KEY_LEN 4
27
28 #define EFACTOR_FACTOR_SW_LEN 17
29 #define EFACTOR_H9_SW_LEN 18
30
31 #define EFACTOR_FACTOR_NAME_PREFIX "Eventide Factor"
32 #define EFACTOR_H9_NAME_PREFIX "Eventide H9"
33
34 #define EFACTOR_PRESET_LINE_SEPARATOR "\x0d\x0a"
35
36 #define EFACTOR_OP_PRESETS_WANT 0x48
37 #define EFACTOR_OP_PROGRAM_WANT 0x4e
38 #define EFACTOR_OP_PRESETS_DUMP 0x49
39
40 #define EFACTOR_PRESET_DUMP_OFFSET 5
41
42 #define EFACTOR_SINGLE_PRESET_MIN_LEN (sizeof(EFACTOR_REQUEST_HEADER) + 5) //The additional 5 bytes are the 2 square brackets and the preset number and the \0 and 0xf7 at the end.
43 #define EFACTOR_SINGLE_PRESET_MAX_LEN 256 //This is an empirical value. The maximum found value is 233 but we just add a few bytes just in case.
44 #define EFACTOR_MAX_ID_TAG_LEN 16 //The longest value is "[100]" plus the \0.
45
46 #define EFACTOR_TIMEOUT_TOTAL_PRESETS 20000 //This takes more than 10s for 100 presets.
47
48 #define EFACTOR_PEDAL_NAME(data) (data->type == EFACTOR_FACTOR ? EFACTOR_FACTOR_NAME_PREFIX : EFACTOR_H9_NAME_PREFIX)
49
50 static const guint8 EVENTIDE_ID[] = { 0x1c };
51 static const guint8 FAMILY_ID[] = { 0, 6 }; //This might not be the same value for all the Factor and H9 pedals.
52 static const guint8 MODEL_ID[] = { 0x11, 0 }; //This might not be the same value for all the Factor and H9 pedals.
53
54 //Identity Request Universal Sysex message. This is the same message used in the backend.
55 //We replicate this here because the compiler can't know the size of an external const array.
56 static const guint8 MIDI_IDENTITY_REQUEST[] =
57 { 0xf0, 0x7e, 0x7f, 6, 1, 0xf7 };
58
59 static const guint8 EFACTOR_REQUEST_HEADER[] = { 0xf0, 0x1c, 0x70, 0 };
60
61 enum efactor_type
62 {
63 EFACTOR_FACTOR,
64 EFACTOR_H9
65 };
66
67 struct efactor_data
68 {
69 guint id;
70 guint presets;
71 guint min;
72 enum efactor_type type;
73 //Readdir data is kept in memory so it can be used in other operations.
74 //In the efactor case, the only way to get a single preset is by getting the panel, which needs a preset to be loaded
75 // but won't work properly if there are preset mappings. So we read all the memory -we were reading it anyway- and
76 // use it to get the download data from there.
77 gchar **lines;
78 };
79
80 struct efactor_iter_data
81 {
82 guint next;
83 guint presets;
84 struct efactor_data *backend_data;
85 };
86
87 enum efactor_fs
88 {
89 FS_EFACTOR_PRESET = 1
90 };
91
92 static GByteArray *
93 efactor_new_op_msg (guint8 op)
94 {
95 GByteArray *tx_msg =
96 g_byte_array_sized_new (sizeof (EFACTOR_REQUEST_HEADER));
97 g_byte_array_append (tx_msg, EFACTOR_REQUEST_HEADER,
98 sizeof (EFACTOR_REQUEST_HEADER) + 2);
99 tx_msg->data[4] = op;
100 tx_msg->data[5] = 0xf7;
101 return tx_msg;
102 }
103
104 static GByteArray *
105 efactor_new_get_msg (guint8 type, const gchar * key)
106 {
107 GByteArray *tx_msg =
108 g_byte_array_sized_new (sizeof (EFACTOR_REQUEST_HEADER));
109 g_byte_array_append (tx_msg, EFACTOR_REQUEST_HEADER,
110 sizeof (EFACTOR_REQUEST_HEADER) + 6);
111 tx_msg->data[4] = type;
112 memcpy (&tx_msg->data[5], key, EFACTOR_KEY_LEN);
113 tx_msg->data[9] = 0xf7;
114 return tx_msg;
115 }
116
117 static gchar *
118 efactor_get_download_path (struct backend *backend,
119 struct item_iterator *remote_iter,
120 const struct fs_operations *ops,
121 const gchar * dst_dir, const gchar * src_path)
122 {
123 gchar *path, *name;
124 struct efactor_data *data = backend->data;
125 gchar *src_path_copy = strdup (src_path);
126 gint id = atoi (basename (src_path_copy));
127 g_free (src_path_copy);
128
129 name = NULL;
130 while (!next_item_iterator (remote_iter))
131 {
132 if (remote_iter->item.id == id)
133 {
134 name = remote_iter->item.name;
135 break;
136 }
137 }
138
139 if (!name)
140 {
141 return NULL;
142 }
143
144 path = malloc (PATH_MAX);
145 snprintf (path, PATH_MAX, "%s/%s %s.syx", dst_dir,
146 EFACTOR_PEDAL_NAME (data), name);
147
148 return path;
149 }
150
151 static guint
152 efactor_next_dentry (struct item_iterator *iter)
153 {
154 struct efactor_iter_data *data = iter->data;
155 struct efactor_data *backend_data = data->backend_data;
156 gchar *preset_name;
157
158 if (data->next == data->presets)
159 {
160 return -ENOENT;
161 }
162
163 iter->item.id = data->next + backend_data->min;
164 preset_name = data->backend_data->lines[data->next * 7 + 6];
165 snprintf (iter->item.name, LABEL_MAX, "%s", preset_name);
166 iter->item.type = ELEKTROID_FILE;
167 iter->item.size = -1;
168 data->next++;
169
170 return 0;
171 }
172
173 static gint
174 efactor_read_dir (struct backend *backend, struct item_iterator *iter,
175 const gchar * path)
176 {
177 GByteArray *tx_msg;
178 GByteArray *rx_msg;
179 struct efactor_iter_data *iter_data;
180 struct efactor_data *data = backend->data;
181
182 if (strcmp (path, "/"))
183 {
184 return -ENOTDIR;
185 }
186
187 if (data->lines)
188 {
189 //Reading from the device switches off and on the internal relays.
190 //In case we call this function again just after calling it, we give the device some time to do it.
191 sleep (1);
192 }
193
194 tx_msg = efactor_new_op_msg (EFACTOR_OP_PRESETS_WANT);
195 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg,
196 EFACTOR_TIMEOUT_TOTAL_PRESETS);
197 if (!rx_msg)
198 {
199 return -ETIMEDOUT;
200 }
201
202 iter_data = g_malloc (sizeof (struct efactor_iter_data));
203 iter_data->next = 0;
204 iter_data->presets = data->presets;
205 iter_data->backend_data = backend->data;
206 if (iter_data->backend_data->lines)
207 {
208 g_strfreev (iter_data->backend_data->lines);
209 }
210 data->lines =
211 g_strsplit ((gchar *) & rx_msg->data[EFACTOR_PRESET_DUMP_OFFSET],
212 EFACTOR_PRESET_LINE_SEPARATOR, -1);
213 free_msg (rx_msg);
214 iter->data = iter_data;
215 iter->next = efactor_next_dentry;
216 iter->free = g_free;
217
218 return 0;
219 }
220
221 static gint
222 efactor_download (struct backend *backend, const gchar * src_path,
223 GByteArray * output, struct job_control *control)
224 {
225 gint err = 0, id;
226 gchar *basename_copy;
227 gboolean active;
228 gchar **lines;
229 struct item_iterator iter;
230 struct efactor_data *data = backend->data;
231
232 control->parts = 1;
233 control->part = 0;
234 set_job_control_progress (control, 0.0);
235
236 if (!data->lines)
237 {
238 err = efactor_read_dir (backend, &iter, "/");
239 if (err)
240 {
241 return err;
242 }
243 free_item_iterator (&iter);
244 }
245
246 basename_copy = strdup (src_path);
247 id = atoi (basename (basename_copy));
248 g_free (basename_copy);
249 if (id < data->min || id >= data->presets)
250 {
251 return -EINVAL;
252 }
253
254 g_byte_array_append (output, EFACTOR_REQUEST_HEADER,
255 sizeof (EFACTOR_REQUEST_HEADER));
256 g_byte_array_append (output, (guint8 *) "\x49", 1); // EFACTOR_OP_PRESETS_DUMP
257 lines = &data->lines[(id - data->min) * 7];
258 for (gint i = 0; i < 7; i++, lines++)
259 {
260 g_byte_array_append (output, (guint8 *) * lines, strlen (*lines));
261 g_byte_array_append (output, (guint8 *) EFACTOR_PRESET_LINE_SEPARATOR,
262 strlen (EFACTOR_PRESET_LINE_SEPARATOR));
263 }
264 g_byte_array_append (output, (guint8 *) "\0\xf7", 2);
265
266 g_mutex_lock (&control->mutex);
267 active = control->active;
268 g_mutex_unlock (&control->mutex);
269
270 if (active)
271 {
272 set_job_control_progress (control, 1.0);
273 }
274 else
275 {
276 err = -ECANCELED;
277 }
278
279 sleep (1);
280
281 return err;
282 }
283
284 static gint
285 efactor_upload (struct backend *backend, const gchar * path,
286 GByteArray * input, struct job_control *control)
287 {
288 gint err = 0, i, id;
289 gchar *name, *b;
290 gboolean active;
291 GByteArray *tx_msg;
292 gchar id_tag[EFACTOR_MAX_ID_TAG_LEN];
293 struct efactor_data *data = backend->data;
294
295 name = strdup (path);
296 id = atoi (basename (name)); //This stops at the ':'.
297 g_free (name);
298
299 control->parts = 1;
300 control->part = 0;
301 set_job_control_progress (control, 0.0);
302
303 //The fourth header byte is the device number ID so it might be different than 0.
304 input->data[sizeof (EFACTOR_REQUEST_HEADER) - 1] = 0;
305 if (input->len > EFACTOR_SINGLE_PRESET_MAX_LEN
306 || input->len <= EFACTOR_SINGLE_PRESET_MIN_LEN
307 || memcmp (input->data, EFACTOR_REQUEST_HEADER,
308 sizeof (EFACTOR_REQUEST_HEADER))
309 || input->data[sizeof (EFACTOR_REQUEST_HEADER)] !=
310 EFACTOR_OP_PRESETS_DUMP)
311 {
312 error_print ("Bad preset\n");
313 err = -EBADMSG;
314 goto end;
315 }
316
317 tx_msg = g_byte_array_sized_new (input->len + 2); // With this we ensure there is enough space for all the digits of the preset number.
318 g_byte_array_append (tx_msg, input->data,
319 sizeof (EFACTOR_REQUEST_HEADER) + 1);
320 tx_msg->data[sizeof (EFACTOR_REQUEST_HEADER) - 1] = (guint8) data->id;
321 snprintf (id_tag, EFACTOR_MAX_ID_TAG_LEN, "[%d]", (id % 100) + 1); //1 based
322 g_byte_array_append (tx_msg, (guint8 *) id_tag, strlen (id_tag));
323
324 i = sizeof (EFACTOR_REQUEST_HEADER) + 1;
325 for (b = (gchar *) & input->data[i]; i < input->len; i++, b++)
326 {
327 if (*b == ' ')
328 {
329 break;
330 }
331 }
332
333 if (i == input->len)
334 {
335 free_msg (tx_msg);
336 err = -EBADMSG;
337 goto end;
338 }
339 g_byte_array_append (tx_msg, (guint8 *) b, input->len - i);
340
341 err = backend_tx (backend, tx_msg);
342
343 g_mutex_lock (&control->mutex);
344 active = control->active;
345 g_mutex_unlock (&control->mutex);
346
347 if (active)
348 {
349 set_job_control_progress (control, 1.0);
350 }
351 else
352 {
353 err = -ECANCELED;
354 }
355
356 end:
357 sleep (1);
358
359 return err;
360 }
361
362 static gint
363 efactor_rename (struct backend *backend, const gchar * src, const gchar * dst)
364 {
365 GByteArray *preset, *rx_msg;
366 guint id;
367 gint err;
368 struct job_control control;
369 gchar **lines, **line;
370 debug_print (1, "Sending rename request...\n");
371 err = common_slot_get_id_name_from_path (src, &id, NULL);
372 if (err)
373 {
374 return err;
375 }
376
377 preset = g_byte_array_new ();
378 //The control initialization is needed.
379 control.active = TRUE;
380 control.callback = NULL;
381 g_mutex_init (&control.mutex);
382 err = efactor_download (backend, src, preset, &control);
383 if (err)
384 {
385 return err;
386 }
387
388 lines = g_strsplit ((gchar *) & preset->data[EFACTOR_PRESET_DUMP_OFFSET],
389 EFACTOR_PRESET_LINE_SEPARATOR, -1);
390 g_free (lines[6]);
391 lines[6] = NULL;
392
393 line = lines;
394 g_byte_array_set_size (preset, EFACTOR_PRESET_DUMP_OFFSET);
395 while (*line)
396 {
397 g_byte_array_append (preset, (guint8 *) (*line), strlen (*line));
398 g_byte_array_append (preset, (guint8 *) EFACTOR_PRESET_LINE_SEPARATOR,
399 strlen (EFACTOR_PRESET_LINE_SEPARATOR));
400 line++;
401 }
402 g_byte_array_append (preset, (guint8 *) dst, strlen (dst));
403 g_byte_array_append (preset, (guint8 *) EFACTOR_PRESET_LINE_SEPARATOR,
404 strlen (EFACTOR_PRESET_LINE_SEPARATOR));
405 g_byte_array_append (preset, (guint8 *) "\0\xf7", 2);
406 g_strfreev (lines);
407
408 rx_msg = backend_tx_and_rx_sysex (backend, preset, 100); //There must be no response.
409 if (rx_msg)
410 {
411 err = -EIO;
412 free_msg (rx_msg);
413 }
414
415 sleep (1);
416
417 return err;
418 }
419
420 static gchar *
421 efactor_get_slot (struct item *item, struct backend *backend)
422 {
423 gchar *slot = malloc (LABEL_MAX);
424 struct efactor_data *data = backend->data;
425 if (data->type == EFACTOR_FACTOR)
426 {
427 snprintf (slot, LABEL_MAX, "[%d:%d]", (item->id / 2) + 1,
428 (item->id % 2) + 1);
429 }
430 else
431 {
432 snprintf (slot, LABEL_MAX, "%d", item->id + 1);
433 }
434 return slot;
435 }
436
437 static void
438 efactor_print (struct item_iterator *iter, struct backend *backend)
439 {
440 gchar *slot = efactor_get_slot (&iter->item, backend);
441 printf ("%c %s %s\n", iter->item.type, slot, iter->item.name);
442 g_free (slot);
443 }
444
445 static const struct fs_operations FS_EFACTOR_OPERATIONS = {
446 .fs = FS_EFACTOR_PRESET,
447 .options = FS_OPTION_SINGLE_OP | FS_OPTION_ID_AS_FILENAME |
448 FS_OPTION_SLOT_STORAGE | FS_OPTION_SORT_BY_ID |
449 FS_OPTION_SHOW_SLOT_COLUMN,
450 .name = "preset",
451 .gui_name = "Presets",
452 .gui_icon = BE_FILE_ICON_SND,
453 .type_ext = "syx",
454 .max_name_len = 16,
455 .readdir = efactor_read_dir,
456 .print_item = efactor_print,
457 .rename = efactor_rename,
458 .download = efactor_download,
459 .upload = efactor_upload,
460 .get_slot = efactor_get_slot,
461 .load = load_file,
462 .save = save_file,
463 .get_ext = backend_get_fs_ext,
464 .get_upload_path = common_slot_get_upload_path,
465 .get_download_path = efactor_get_download_path
466 };
467
468 static const struct fs_operations *FS_EFACTOR_OPERATIONS_LIST[] = {
469 &FS_EFACTOR_OPERATIONS, NULL
470 };
471
472 void
473 efactor_destroy_data (struct backend *backend)
474 {
475 struct efactor_data *data = backend->data;
476 if (data->lines)
477 {
478 g_strfreev (data->lines);
479 }
480 backend_destroy_data (backend);
481 }
482
483 //We are replicanting the functionality in the backend because the request is standard but the response is not.
484 gint
485 efactor_handshake (struct backend *backend)
486 {
487 gint swlen, max, min, presets, id;
488 enum efactor_type type;
489 struct efactor_data *data;
490 GByteArray *tx_msg;
491 GByteArray *rx_msg;
492
493 //Sometimes it takes a lot of time to receive the response to the MIDI identity request.
494 //As the backend is already asking for it, we need to ensure that the input buffer is empty before continuing.
495 //With these two calls, the total timeout including the backend handshake is 2.5 s, which is empirically enough.
496 g_mutex_lock (&backend->mutex);
497 backend_rx_drain (backend);
498 backend_rx_drain (backend);
499 g_mutex_unlock (&backend->mutex);
500
501 tx_msg = g_byte_array_sized_new (sizeof (MIDI_IDENTITY_REQUEST));
502 g_byte_array_append (tx_msg, (guchar *) MIDI_IDENTITY_REQUEST,
503 sizeof (MIDI_IDENTITY_REQUEST));
504 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1);
505 if (!rx_msg)
506 {
507 return -ENODEV;
508 }
509
510 if (rx_msg->data[4] == 2)
511 {
512 if (rx_msg->len > 15)
513 {
514 memset (backend->midi_info.company, 0, BE_COMPANY_LEN);
515 memcpy (backend->midi_info.company, &rx_msg->data[5], 1);
516 memcpy (backend->midi_info.family, &rx_msg->data[6], BE_FAMILY_LEN);
517 memcpy (backend->midi_info.model, &rx_msg->data[8], BE_MODEL_LEN);
518 memcpy (backend->midi_info.version, &rx_msg->data[10],
519 BE_VERSION_LEN);
520
521 snprintf (backend->device_name, LABEL_MAX,
522 "%02x-%02x-%02x %02x-%02x %02x-%02x %d.%d.%d.%d",
523 backend->midi_info.company[0],
524 backend->midi_info.company[1],
525 backend->midi_info.company[2],
526 backend->midi_info.family[0],
527 backend->midi_info.family[1],
528 backend->midi_info.model[0],
529 backend->midi_info.model[1],
530 backend->midi_info.version[0],
531 backend->midi_info.version[1],
532 backend->midi_info.version[2],
533 backend->midi_info.version[3]);
534 snprintf (backend->device_desc.name, LABEL_MAX, "%s",
535 backend->device_name);
536 debug_print (1, "XML version:\n%s\n", &rx_msg->data[14]);
537 }
538 else
539 {
540 debug_print (1, "Illegal MIDI identity reply length\n");
541 }
542 }
543 else
544 {
545 debug_print (1, "Illegal SUB-ID2\n");
546 }
547
548 free_msg (rx_msg);
549
550 if (memcmp (backend->midi_info.company, EVENTIDE_ID, sizeof (EVENTIDE_ID))
551 || memcmp (backend->midi_info.family, FAMILY_ID, sizeof (FAMILY_ID))
552 || memcmp (backend->midi_info.model, MODEL_ID, sizeof (MODEL_ID)))
553 {
554 return -ENODEV;
555 }
556
557 tx_msg = efactor_new_get_msg (EFACTOR_MSG_TYPE_OBJECT, "0000"); //tj_version_key
558 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1);
559 id = rx_msg->data[sizeof (EFACTOR_REQUEST_HEADER) - 1];
560 debug_print (1, "Version: %s\n", &rx_msg->data[7]);
561 free_msg (rx_msg);
562
563 tx_msg = efactor_new_get_msg (EFACTOR_MSG_TYPE_VALUE, "0001"); //tj_switch_key
564 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1);
565 debug_print (1, "Switches: %s\n", &rx_msg->data[7]);
566 swlen = strlen ((gchar *) & rx_msg->data[7]) - 2; //Remove single quotes
567 free_msg (rx_msg);
568
569 tx_msg = efactor_new_get_msg (EFACTOR_MSG_TYPE_OBJECT, "0206"); //sp_num_banks_lo
570 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1);
571 debug_print (1, "Minimum value: %s\n", &rx_msg->data[7]);
572 min = atoi ((gchar *) & rx_msg->data[9]);
573 free_msg (rx_msg);
574
575 tx_msg = efactor_new_get_msg (EFACTOR_MSG_TYPE_OBJECT, "020A"); //sp_num_banks
576 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1);
577 debug_print (1, "Maximum value: %s\n", &rx_msg->data[7]);
578 max = atoi ((gchar *) & rx_msg->data[9]);
579 free_msg (rx_msg);
580
581 if (swlen == EFACTOR_FACTOR_SW_LEN)
582 {
583 debug_print (1, "Factor pedal detected\n");
584 min = 2 * min;
585 max = 2 * (max + 1);
586 type = EFACTOR_FACTOR;
587 }
588 else if (swlen == EFACTOR_H9_SW_LEN)
589 {
590 debug_print (1, "H9 pedal detected\n");
591 type = EFACTOR_H9;
592 }
593 else
594 {
595 error_print ("Illegal switches number %d\n", swlen);
596 return -ENODEV;
597 }
598
599 presets = max - min;
600 debug_print (1, "Total presets: %d [%d, %d]\n", presets, min, max - 1);
601
602 data = g_malloc (sizeof (struct efactor_data));
603 data->id = id;
604 data->presets = presets;
605 data->min = min;
606 data->type = type;
607 data->lines = NULL;
608
609 backend->device_desc.filesystems = FS_EFACTOR_PRESET;
610 backend->fs_ops = FS_EFACTOR_OPERATIONS_LIST;
611 backend->destroy_data = efactor_destroy_data;
612 backend->data = data;
613
614 snprintf (backend->device_name, LABEL_MAX, "%s %d.%d.%d.%d",
615 EFACTOR_PEDAL_NAME (data), backend->midi_info.version[0],
616 backend->midi_info.version[1], backend->midi_info.version[2],
617 backend->midi_info.version[3]);
618
619 return 0;
620 }
0 /*
1 * efactor.h
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef EFACTOR_H
21 #define EFACTOR_H
22
23 #include "backend.h"
24
25 gint efactor_handshake (struct backend *);
26
27 #endif
0 /*
1 * elektron.c
2 * Copyright (C) 2019 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <math.h>
22 #include <endian.h>
23 #include <poll.h>
24 #include <zlib.h>
25 #include <libgen.h>
26 #include "elektron.h"
27 #include "elektron.h"
28 #include "utils.h"
29 #include "sample.h"
30 #include "package.h"
31 #include "../config.h"
32
33 #define DEVICES_FILE "/elektron-devices.json"
34
35 #define DEV_TAG_ID "id"
36 #define DEV_TAG_NAME "name"
37 #define DEV_TAG_ALIAS "alias"
38 #define DEV_TAG_FILESYSTEMS "filesystems"
39 #define DEV_TAG_STORAGE "storage"
40
41 static const gchar *FS_TYPE_NAMES[] = { "+Drive", "RAM" };
42
43 #define DATA_TRANSF_BLOCK_BYTES 0x2000
44 #define OS_TRANSF_BLOCK_BYTES 0x800
45 #define MAX_ZIP_SIZE (128 * 1024 * 1024)
46
47 #define FS_DATA_PRJ_PREFIX "/projects"
48 #define FS_DATA_SND_PREFIX "/soundbanks"
49 #define FS_SAMPLES_START_POS 5
50 #define FS_DATA_START_POS 18
51 #define FS_SAMPLES_SIZE_POS_W 21
52 #define FS_SAMPLES_LAST_FRAME_POS_W 33
53 #define FS_SAMPLES_PAD_RES 22
54
55 #define ELEKTRON_NAME_MAX_LEN 32
56
57 #define ELEKTRON_SAMPLE_INFO_PAD_I32_LEN 10
58 #define ELEKTRON_LOOP_TYPE 0x7f
59
60 struct elektron_sample_header
61 {
62 guint32 type;
63 guint32 sample_len_bytes;
64 guint32 samplerate;
65 guint32 loopstart;
66 guint32 loopend;
67 guint32 looptype;
68 guint32 padding[ELEKTRON_SAMPLE_INFO_PAD_I32_LEN];
69 };
70
71 struct elektron_iterator_data
72 {
73 GByteArray *msg;
74 guint32 pos;
75 guint32 hash;
76 guint16 operations;
77 guint8 has_valid_data;
78 guint8 has_metadata;
79 guint32 fs;
80 gboolean cached;
81 };
82
83 enum elektron_storage
84 {
85 STORAGE_PLUS_DRIVE = 0x1,
86 STORAGE_RAM = 0x2
87 };
88
89 struct elektron_data
90 {
91 guint16 seq;
92 gchar fw_version[LABEL_MAX];
93 };
94
95 typedef GByteArray *(*elektron_msg_id_func) (guint);
96
97 typedef GByteArray *(*elektron_msg_id_len_func) (guint, guint);
98
99 typedef GByteArray *(*elektron_msg_path_func) (const gchar *);
100
101 typedef GByteArray *(*elektron_msg_path_len_func) (const gchar *, guint);
102
103 typedef GByteArray *(*elektron_msg_read_blk_func) (guint, guint, guint);
104
105 typedef GByteArray *(*elektron_msg_write_blk_func) (guint, GByteArray *,
106 guint *, guint, void *);
107
108 typedef void (*elektron_copy_array) (GByteArray *, GByteArray *);
109
110 typedef gint (*elektron_path_func) (struct backend *, const gchar *);
111
112 typedef gint (*elektron_src_dst_func) (struct backend *, const gchar *,
113 const gchar *);
114
115 static gint elektron_delete_samples_dir (struct backend *, const gchar *);
116 static gint elektron_read_samples_dir (struct backend *,
117 struct item_iterator *, const gchar *);
118 static gint elektron_create_samples_dir (struct backend *, const gchar *);
119 static gint elektron_delete_samples_item (struct backend *, const gchar *);
120 static gint elektron_move_samples_item (struct backend *, const gchar *,
121 const gchar *);
122 static gint elektron_download_sample (struct backend *, const gchar *,
123 GByteArray *, struct job_control *);
124 static gint elektron_upload_sample (struct backend *, const gchar *,
125 GByteArray *, struct job_control *);
126
127 static gint elektron_delete_raw_dir (struct backend *, const gchar *);
128 static gint elektron_read_raw_dir (struct backend *, struct item_iterator *,
129 const gchar *);
130 static gint elektron_create_raw_dir (struct backend *, const gchar *);
131 static gint elektron_delete_raw_item (struct backend *, const gchar *);
132 static gint elektron_move_raw_item (struct backend *, const gchar *,
133 const gchar *);
134 static gint elektron_download_raw (struct backend *, const gchar *,
135 GByteArray *, struct job_control *);
136 static gint elektron_upload_raw (struct backend *, const gchar *,
137 GByteArray *, struct job_control *);
138
139 static gint elektron_read_data_dir_any (struct backend *,
140 struct item_iterator *,
141 const gchar *);
142 static gint elektron_read_data_dir_prj (struct backend *,
143 struct item_iterator *,
144 const gchar *);
145 static gint elektron_read_data_dir_snd (struct backend *,
146 struct item_iterator *,
147 const gchar *);
148
149 static gint elektron_move_data_item_any (struct backend *, const gchar *,
150 const gchar *);
151 static gint elektron_move_data_item_prj (struct backend *, const gchar *,
152 const gchar *);
153 static gint elektron_move_data_item_snd (struct backend *, const gchar *,
154 const gchar *);
155
156 static gint elektron_copy_data_item_any (struct backend *, const gchar *,
157 const gchar *);
158 static gint elektron_copy_data_item_prj (struct backend *, const gchar *,
159 const gchar *);
160 static gint elektron_copy_data_item_snd (struct backend *, const gchar *,
161 const gchar *);
162
163 static gint elektron_clear_data_item_any (struct backend *, const gchar *);
164 static gint elektron_clear_data_item_prj (struct backend *, const gchar *);
165 static gint elektron_clear_data_item_snd (struct backend *, const gchar *);
166
167 static gint elektron_swap_data_item_any (struct backend *, const gchar *,
168 const gchar *);
169 static gint elektron_swap_data_item_prj (struct backend *, const gchar *,
170 const gchar *);
171 static gint elektron_swap_data_item_snd (struct backend *, const gchar *,
172 const gchar *);
173
174 static gint elektron_download_data_any (struct backend *, const gchar *,
175 GByteArray *, struct job_control *);
176 static gint elektron_download_data_snd_pkg (struct backend *, const gchar *,
177 GByteArray *,
178 struct job_control *);
179 static gint elektron_download_data_prj_pkg (struct backend *, const gchar *,
180 GByteArray *,
181 struct job_control *);
182 static gint elektron_download_raw_pst_pkg (struct backend *, const gchar *,
183 GByteArray *,
184 struct job_control *);
185
186 static gint elektron_upload_data_any (struct backend *, const gchar *,
187 GByteArray *, struct job_control *);
188 static gint elektron_upload_data_prj_pkg (struct backend *, const gchar *,
189 GByteArray *, struct job_control *);
190 static gint elektron_upload_data_snd_pkg (struct backend *, const gchar *,
191 GByteArray *, struct job_control *);
192 static gint elektron_upload_raw_pst_pkg (struct backend *, const gchar *,
193 GByteArray *, struct job_control *);
194
195 static gint elektron_copy_iterator (struct item_iterator *,
196 struct item_iterator *, gboolean);
197
198 static gchar *elektron_get_dev_and_fs_ext (const struct device_desc *,
199 const struct fs_operations *);
200
201 static gchar *elektron_get_upload_path_smplrw (struct backend *,
202 struct item_iterator *,
203 const struct fs_operations *,
204 const gchar *, const gchar *,
205 gint32 *);
206 static gchar *elektron_get_upload_path_data (struct backend *,
207 struct item_iterator *,
208 const struct fs_operations *,
209 const gchar *, const gchar *,
210 gint32 *);
211 static gchar *elektron_get_download_path (struct backend *,
212 struct item_iterator *,
213 const struct fs_operations *,
214 const gchar *, const gchar *);
215 static gchar *elektron_get_download_name (struct backend *,
216 struct item_iterator *,
217 const struct fs_operations *,
218 const gchar *);
219
220 static gint elektron_upgrade_os (struct backend *, struct sysex_transfer *);
221
222 static gint elektron_sample_load (const gchar *, GByteArray *,
223 struct job_control *);
224
225 static enum item_type elektron_get_path_type (struct backend *,
226 const gchar *,
227 fs_init_iter_func);
228
229 static void elektron_print_smplrw (struct item_iterator *, struct backend *);
230
231 static void elektron_print_data (struct item_iterator *, struct backend *);
232
233 static const guint8 MSG_HEADER[] = { 0xf0, 0, 0x20, 0x3c, 0x10, 0 };
234
235 static const guint8 PING_REQUEST[] = { 0x1 };
236 static const guint8 SOFTWARE_VERSION_REQUEST[] = { 0x2 };
237 static const guint8 DEVICEUID_REQUEST[] = { 0x3 };
238 static const guint8 STORAGEINFO_REQUEST[] = { 0x5 };
239
240 static const guint8 FS_SAMPLE_READ_DIR_REQUEST[] = { 0x10 };
241 static const guint8 FS_SAMPLE_CREATE_DIR_REQUEST[] = { 0x11 };
242 static const guint8 FS_SAMPLE_DELETE_DIR_REQUEST[] = { 0x12 };
243 static const guint8 FS_SAMPLE_DELETE_FILE_REQUEST[] = { 0x20 };
244 static const guint8 FS_SAMPLE_RENAME_FILE_REQUEST[] = { 0x21 };
245 static const guint8 FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST[] =
246 { 0x23, 0, 0, 0, 0, 0, 0, 0, 0 };
247 static const guint8 FS_SAMPLE_OPEN_FILE_READER_REQUEST[] = { 0x30 };
248 static const guint8 FS_SAMPLE_CLOSE_FILE_READER_REQUEST[] = { 0x31 };
249 static const guint8 FS_SAMPLE_READ_FILE_REQUEST[] =
250 { 0x32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
251 static const guint8 FS_SAMPLE_OPEN_FILE_WRITER_REQUEST[] =
252 { 0x40, 0, 0, 0, 0 };
253 static const guint8 FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST[] =
254 { 0x41, 0, 0, 0, 0, 0, 0, 0, 0 };
255 static const guint8 FS_SAMPLE_WRITE_FILE_REQUEST[] =
256 { 0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
257
258 static const guint8 FS_RAW_READ_DIR_REQUEST[] = { 0x14 };
259 static const guint8 FS_RAW_CREATE_DIR_REQUEST[] = { 0x15 };
260 static const guint8 FS_RAW_DELETE_DIR_REQUEST[] = { 0x16 };
261 static const guint8 FS_RAW_DELETE_FILE_REQUEST[] = { 0x24 };
262 static const guint8 FS_RAW_RENAME_FILE_REQUEST[] = { 0x25 };
263 static const guint8 FS_RAW_OPEN_FILE_READER_REQUEST[] = { 0x33 };
264 static const guint8 FS_RAW_CLOSE_FILE_READER_REQUEST[] = { 0x34 };
265 static const guint8 FS_RAW_READ_FILE_REQUEST[] =
266 { 0x35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
267 static const guint8 FS_RAW_OPEN_FILE_WRITER_REQUEST[] = { 0x43, 0, 0, 0, 0 };
268 static const guint8 FS_RAW_CLOSE_FILE_WRITER_REQUEST[] =
269 { 0x44, 0, 0, 0, 0, 0, 0, 0, 0 };
270 static const guint8 FS_RAW_WRITE_FILE_REQUEST[] =
271 { 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
272
273 static const guint8 DATA_LIST_REQUEST[] = { 0x53 };
274 static const guint8 DATA_READ_OPEN_REQUEST[] = { 0x54 };
275 static const guint8 DATA_READ_PARTIAL_REQUEST[] = { 0x55 };
276 static const guint8 DATA_READ_CLOSE_REQUEST[] = { 0x56 };
277 static const guint8 DATA_WRITE_OPEN_REQUEST[] = { 0x57 };
278 static const guint8 DATA_WRITE_PARTIAL_REQUEST[] = { 0x58 };
279 static const guint8 DATA_WRITE_CLOSE_REQUEST[] = { 0x59 };
280 static const guint8 DATA_MOVE_REQUEST[] = { 0x5a };
281 static const guint8 DATA_COPY_REQUEST[] = { 0x5b };
282 static const guint8 DATA_CLEAR_REQUEST[] = { 0x5c };
283 static const guint8 DATA_SWAP_REQUEST[] = { 0x5d };
284 static const guint8 OS_UPGRADE_START_REQUEST[] =
285 { 0x50, 0, 0, 0, 0, 's', 'y', 's', 'e', 'x', '\0', 1 };
286 static const guint8 OS_UPGRADE_WRITE_RESPONSE[] =
287 { 0x51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
288
289 static const struct fs_operations FS_SAMPLES_OPERATIONS = {
290 .fs = FS_SAMPLES,
291 .options = FS_OPTION_AUDIO_PLAYER | FS_OPTION_STEREO |
292 FS_OPTION_SORT_BY_NAME | FS_OPTION_SHOW_SIZE_COLUMN,
293 .name = "sample",
294 .gui_name = "Samples",
295 .gui_icon = BE_FILE_ICON_WAVE,
296 .type_ext = "wav",
297 .max_name_len = ELEKTRON_NAME_MAX_LEN,
298 .readdir = elektron_read_samples_dir,
299 .print_item = elektron_print_smplrw,
300 .mkdir = elektron_create_samples_dir,
301 .delete = elektron_delete_samples_item,
302 .rename = elektron_move_samples_item,
303 .move = elektron_move_samples_item,
304 .download = elektron_download_sample,
305 .upload = elektron_upload_sample,
306 .load = elektron_sample_load,
307 .save = sample_save_from_array,
308 .get_ext = backend_get_fs_ext,
309 .get_upload_path = elektron_get_upload_path_smplrw,
310 .get_download_path = elektron_get_download_path
311 };
312
313 static const struct fs_operations FS_RAW_ANY_OPERATIONS = {
314 .fs = FS_RAW_ALL,
315 .options = 0,
316 .name = "raw",
317 .type_ext = "raw",
318 .max_name_len = ELEKTRON_NAME_MAX_LEN,
319 .readdir = elektron_read_raw_dir,
320 .print_item = elektron_print_smplrw,
321 .mkdir = elektron_create_raw_dir,
322 .delete = elektron_delete_raw_item,
323 .rename = elektron_move_raw_item,
324 .move = elektron_move_raw_item,
325 .download = elektron_download_raw,
326 .upload = elektron_upload_raw,
327 .load = load_file,
328 .save = save_file,
329 .get_ext = elektron_get_dev_and_fs_ext,
330 .get_upload_path = elektron_get_upload_path_smplrw,
331 .get_download_path = elektron_get_download_path
332 };
333
334 static const struct fs_operations FS_RAW_PRESETS_OPERATIONS = {
335 .fs = FS_RAW_PRESETS,
336 .options = 0,
337 .name = "preset",
338 .gui_name = "Presets",
339 .gui_icon = BE_FILE_ICON_SND,
340 .type_ext = "pst",
341 .max_name_len = ELEKTRON_NAME_MAX_LEN,
342 .readdir = elektron_read_raw_dir,
343 .print_item = elektron_print_smplrw,
344 .mkdir = elektron_create_raw_dir,
345 .delete = elektron_delete_raw_item,
346 .rename = elektron_move_raw_item,
347 .move = elektron_move_raw_item,
348 .download = elektron_download_raw_pst_pkg,
349 .upload = elektron_upload_raw_pst_pkg,
350 .load = load_file,
351 .save = save_file,
352 .get_ext = elektron_get_dev_and_fs_ext,
353 .get_upload_path = elektron_get_upload_path_smplrw,
354 .get_download_path = elektron_get_download_path
355 };
356
357 static const struct fs_operations FS_DATA_ANY_OPERATIONS = {
358 .fs = FS_DATA_ALL,
359 .options = FS_OPTION_SORT_BY_ID | FS_OPTION_ID_AS_FILENAME,
360 .name = "data",
361 .type_ext = "data",
362 .readdir = elektron_read_data_dir_any,
363 .print_item = elektron_print_data,
364 .delete = elektron_clear_data_item_any,
365 .move = elektron_move_data_item_any,
366 .copy = elektron_copy_data_item_any,
367 .clear = elektron_clear_data_item_any,
368 .swap = elektron_swap_data_item_any,
369 .download = elektron_download_data_any,
370 .upload = elektron_upload_data_any,
371 .load = load_file,
372 .save = save_file,
373 .get_ext = elektron_get_dev_and_fs_ext,
374 .get_upload_path = elektron_get_upload_path_data,
375 .get_download_path = elektron_get_download_path
376 };
377
378 static const struct fs_operations FS_DATA_PRJ_OPERATIONS = {
379 .fs = FS_DATA_PRJ,
380 .options = FS_OPTION_SORT_BY_ID | FS_OPTION_ID_AS_FILENAME |
381 FS_OPTION_SHOW_SIZE_COLUMN,
382 .name = "project",
383 .gui_name = "Projects",
384 .gui_icon = BE_FILE_ICON_PRJ,
385 .type_ext = "prj",
386 .readdir = elektron_read_data_dir_prj,
387 .print_item = elektron_print_data,
388 .delete = elektron_clear_data_item_prj,
389 .move = elektron_move_data_item_prj,
390 .copy = elektron_copy_data_item_prj,
391 .clear = elektron_clear_data_item_prj,
392 .swap = elektron_swap_data_item_prj,
393 .download = elektron_download_data_prj_pkg,
394 .upload = elektron_upload_data_prj_pkg,
395 .load = load_file,
396 .save = save_file,
397 .get_ext = elektron_get_dev_and_fs_ext,
398 .get_upload_path = elektron_get_upload_path_data,
399 .get_download_path = elektron_get_download_path
400 };
401
402 static const struct fs_operations FS_DATA_SND_OPERATIONS = {
403 .fs = FS_DATA_SND,
404 .options = FS_OPTION_SORT_BY_ID | FS_OPTION_ID_AS_FILENAME |
405 FS_OPTION_SHOW_SIZE_COLUMN,
406 .name = "sound",
407 .gui_name = "Sounds",
408 .gui_icon = BE_FILE_ICON_SND,
409 .type_ext = "snd",
410 .readdir = elektron_read_data_dir_snd,
411 .print_item = elektron_print_data,
412 .delete = elektron_clear_data_item_snd,
413 .move = elektron_move_data_item_snd,
414 .copy = elektron_copy_data_item_snd,
415 .clear = elektron_clear_data_item_snd,
416 .swap = elektron_swap_data_item_snd,
417 .download = elektron_download_data_snd_pkg,
418 .upload = elektron_upload_data_snd_pkg,
419 .load = load_file,
420 .save = save_file,
421 .get_ext = elektron_get_dev_and_fs_ext,
422 .get_upload_path = elektron_get_upload_path_data,
423 .get_download_path = elektron_get_download_path
424 };
425
426 static const struct fs_operations *FS_OPERATIONS[] = {
427 &FS_SAMPLES_OPERATIONS, &FS_RAW_ANY_OPERATIONS, &FS_RAW_PRESETS_OPERATIONS,
428 &FS_DATA_ANY_OPERATIONS, &FS_DATA_PRJ_OPERATIONS, &FS_DATA_SND_OPERATIONS,
429 NULL
430 };
431
432 static void
433 elektron_print_smplrw (struct item_iterator *iter, struct backend *backend)
434 {
435 gchar *hsize = get_human_size (iter->item.size, FALSE);
436 struct elektron_iterator_data *data = iter->data;
437
438 printf ("%c %10s %08x %s\n", iter->item.type,
439 hsize, data->hash, iter->item.name);
440 g_free (hsize);
441 }
442
443 static void
444 elektron_print_data (struct item_iterator *iter, struct backend *backend)
445 {
446 gchar *hsize = get_human_size (iter->item.size, FALSE);
447 struct elektron_iterator_data *data = iter->data;
448
449 printf ("%c %3d %04x %d %d %10s %s\n", iter->item.type,
450 iter->item.id, data->operations, data->has_valid_data,
451 data->has_metadata, hsize, iter->item.name);
452 g_free (hsize);
453 }
454
455 static void
456 elektron_free_iterator_data (void *iter_data)
457 {
458 struct elektron_iterator_data *data = iter_data;
459
460 if (!data->cached)
461 {
462 free_msg (data->msg);
463 }
464 g_free (data);
465 }
466
467 static inline void
468 elektron_get_utf8 (gchar * dst, const gchar * s)
469 {
470 gchar *aux = g_convert (s, -1, "UTF8", "CP1252", NULL, NULL, NULL);
471 snprintf (dst, LABEL_MAX, "%s", aux);
472 g_free (aux);
473 }
474
475 static inline gchar *
476 elektron_get_cp1252 (const gchar * s)
477 {
478 return g_convert (s, -1, "CP1252", "UTF8", NULL, NULL, NULL);
479 }
480
481 static inline guint8
482 elektron_get_msg_status (const GByteArray * msg)
483 {
484 return msg->data[5];
485 }
486
487 static inline gchar *
488 elektron_get_msg_string (const GByteArray * msg)
489 {
490 return (gchar *) & msg->data[6];
491 }
492
493 static guint
494 elektron_next_smplrw_entry (struct item_iterator *iter)
495 {
496 guint32 *data32;
497 gchar *name_cp1252;
498 struct elektron_iterator_data *data = iter->data;
499
500 if (data->pos == data->msg->len)
501 {
502 return -ENOENT;
503 }
504 else
505 {
506 data32 = (guint32 *) & data->msg->data[data->pos];
507 data->hash = be32toh (*data32);
508 data->pos += sizeof (guint32);
509
510 data32 = (guint32 *) & data->msg->data[data->pos];
511 iter->item.size = be32toh (*data32);
512 data->pos += sizeof (guint32);
513
514 data->pos++; //write_protected
515
516 iter->item.type = data->msg->data[data->pos];
517 data->pos++;
518
519 name_cp1252 = (gchar *) & data->msg->data[data->pos];
520 elektron_get_utf8 (iter->item.name, name_cp1252);
521 if (data->fs == FS_RAW_ALL && iter->item.type == ELEKTROID_FILE)
522 {
523 //This eliminates the extension ".mc-snd" that the device provides.
524 iter->item.name[strlen (iter->item.name) - 7] = 0;
525 }
526 data->pos += strlen (name_cp1252) + 1;
527
528 iter->item.id = -1;
529
530 return 0;
531 }
532 }
533
534 static gint elektron_copy_iterator (struct item_iterator *,
535 struct item_iterator *, gboolean);
536
537 static gint
538 elektron_init_iterator (struct item_iterator *iter, GByteArray * msg,
539 iterator_next next, enum elektron_fs fs,
540 gboolean cached)
541 {
542 struct elektron_iterator_data *data =
543 malloc (sizeof (struct elektron_iterator_data));
544
545 data->msg = msg;
546 data->pos = fs == FS_DATA_ALL ? FS_DATA_START_POS : FS_SAMPLES_START_POS;
547 data->fs = fs;
548 data->cached = cached;
549
550 iter->data = data;
551 iter->next = next;
552 iter->free = elektron_free_iterator_data;
553 iter->copy = elektron_copy_iterator;
554 iter->item.id = -1;
555
556 return 0;
557 }
558
559 static gint
560 elektron_copy_iterator (struct item_iterator *dst, struct item_iterator *src,
561 gboolean cached)
562 {
563 GByteArray *array;
564 struct elektron_iterator_data *data = src->data;
565 if (cached)
566 {
567 array = data->msg;
568 }
569 else
570 {
571 array = g_byte_array_sized_new (data->msg->len);
572 g_byte_array_append (array, data->msg->data, data->msg->len);
573 }
574 return elektron_init_iterator (dst, array, src->next, data->fs, cached);
575 }
576
577 static GByteArray *
578 elektron_decode_payload (const GByteArray * src)
579 {
580 GByteArray *dst;
581 int i, j, k, dst_len;
582 unsigned int shift;
583
584 dst_len = src->len - ceill (src->len / 8.0);
585 dst = g_byte_array_new ();
586 g_byte_array_set_size (dst, dst_len);
587
588 for (i = 0, j = 0; i < src->len; i += 8, j += 7)
589 {
590 shift = 0x40;
591 for (k = 0; k < 7 && i + k + 1 < src->len; k++)
592 {
593 dst->data[j + k] =
594 src->data[i + k + 1] | (src->data[i] & shift ? 0x80 : 0);
595 shift = shift >> 1;
596 }
597 }
598
599 return dst;
600 }
601
602 static GByteArray *
603 elektron_encode_payload (const GByteArray * src)
604 {
605 GByteArray *dst;
606 int i, j, k, dst_len;
607 unsigned int accum;
608
609 dst_len = src->len + ceill (src->len / 7.0);
610 dst = g_byte_array_new ();
611 g_byte_array_set_size (dst, dst_len);
612
613 for (i = 0, j = 0; j < src->len; i += 8, j += 7)
614 {
615 accum = 0;
616 for (k = 0; k < 7; k++)
617 {
618 accum = accum << 1;
619 if (j + k < src->len)
620 {
621 if (src->data[j + k] & 0x80)
622 {
623 accum |= 1;
624 }
625 dst->data[i + k + 1] = src->data[j + k] & 0x7f;
626 }
627 }
628 dst->data[i] = accum;
629 }
630
631 return dst;
632 }
633
634 static GByteArray *
635 elektron_msg_to_raw (const GByteArray * msg)
636 {
637 GByteArray *encoded;
638 GByteArray *sysex = g_byte_array_new ();
639
640 g_byte_array_append (sysex, MSG_HEADER, sizeof (MSG_HEADER));
641 encoded = elektron_encode_payload (msg);
642 g_byte_array_append (sysex, encoded->data, encoded->len);
643 free_msg (encoded);
644 g_byte_array_append (sysex, (guint8 *) "\xf7", 1);
645
646 return sysex;
647 }
648
649 static gint
650 elektron_get_smplrw_info_from_msg (GByteArray * info_msg, guint32 * id,
651 guint * size)
652 {
653 if (elektron_get_msg_status (info_msg))
654 {
655 if (id)
656 {
657 *id = be32toh (*((guint32 *) & info_msg->data[6]));
658 }
659 if (size)
660 {
661 *size = be32toh (*((guint32 *) & info_msg->data[10]));
662 }
663 }
664 else
665 {
666 if (id)
667 {
668 return -EIO;
669 }
670 }
671
672 return 0;
673 }
674
675 static GByteArray *
676 elektron_new_msg (const guint8 * data, guint len)
677 {
678 GByteArray *msg = g_byte_array_new ();
679
680 g_byte_array_append (msg, (guchar *) "\0\0\0\0", 4);
681 g_byte_array_append (msg, data, len);
682
683 return msg;
684 }
685
686 static GByteArray *
687 elektron_new_msg_uint8 (const guint8 * data, guint len, guint8 type)
688 {
689 GByteArray *msg = elektron_new_msg (data, len);
690
691 g_byte_array_append (msg, &type, 1);
692
693 return msg;
694 }
695
696 static GByteArray *
697 elektron_new_msg_path (const guint8 * data, guint len, const gchar * path)
698 {
699 GByteArray *msg;
700 gchar *path_cp1252 = elektron_get_cp1252 (path);
701
702 if (!path_cp1252)
703 {
704 return NULL;
705 }
706
707 msg = elektron_new_msg (data, len);
708 g_byte_array_append (msg, (guchar *) path_cp1252, strlen (path_cp1252) + 1);
709 g_free (path_cp1252);
710
711 return msg;
712 }
713
714 static GByteArray *
715 elektron_new_msg_close_common_read (const guint8 * data, guint len, guint id)
716 {
717 guint32 aux32;
718 GByteArray *msg = elektron_new_msg (data, len);
719
720 aux32 = htobe32 (id);
721 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
722 return msg;
723 }
724
725 static GByteArray *
726 elektron_new_msg_close_sample_read (guint id)
727 {
728 return
729 elektron_new_msg_close_common_read (FS_SAMPLE_CLOSE_FILE_READER_REQUEST,
730 sizeof
731 (FS_SAMPLE_CLOSE_FILE_READER_REQUEST),
732 id);
733 }
734
735 static GByteArray *
736 elektron_new_msg_close_raw_read (guint id)
737 {
738 return
739 elektron_new_msg_close_common_read (FS_RAW_CLOSE_FILE_READER_REQUEST,
740 sizeof
741 (FS_RAW_CLOSE_FILE_READER_REQUEST),
742 id);
743 }
744
745 static GByteArray *
746 elektron_new_msg_open_common_write (const guint8 * data, guint len,
747 const gchar * path, guint bytes)
748 {
749 guint32 aux32;
750 GByteArray *msg = elektron_new_msg_path (data, len, path);
751
752 aux32 = htobe32 (bytes);
753 memcpy (&msg->data[5], &aux32, sizeof (guint32));
754
755 return msg;
756 }
757
758 static GByteArray *
759 elektron_new_msg_open_sample_write (const gchar * path, guint bytes)
760 {
761 return
762 elektron_new_msg_open_common_write (FS_SAMPLE_OPEN_FILE_WRITER_REQUEST,
763 sizeof
764 (FS_SAMPLE_OPEN_FILE_WRITER_REQUEST),
765 path,
766 bytes +
767 sizeof (struct
768 elektron_sample_header));
769 }
770
771 static GByteArray *
772 elektron_new_msg_open_raw_write (const gchar * path, guint bytes)
773 {
774 return elektron_new_msg_open_common_write (FS_RAW_OPEN_FILE_WRITER_REQUEST,
775 sizeof
776 (FS_RAW_OPEN_FILE_WRITER_REQUEST),
777 path, bytes);
778 }
779
780
781 static GByteArray *
782 elektron_new_msg_list (const gchar * path, int32_t start_index,
783 int32_t end_index, gboolean all)
784 {
785 guint32 aux32;
786 guint8 aux8;
787 GByteArray *msg = elektron_new_msg_path (DATA_LIST_REQUEST,
788 sizeof (DATA_LIST_REQUEST),
789 path);
790
791 aux32 = htobe32 (start_index);
792 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
793 aux32 = htobe32 (end_index);
794 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
795 aux8 = all;
796 g_byte_array_append (msg, (guchar *) & aux8, sizeof (guint8));
797
798 return msg;
799 }
800
801 static GByteArray *
802 elektron_new_msg_write_sample_blk (guint id, GByteArray * sample,
803 guint * total, guint seq, void *data)
804 {
805 guint32 aux32;
806 guint16 aux16, *aux16p;
807 int i, consumed, bytes_blk;
808 struct sample_info *sample_info = data;
809 struct elektron_sample_header elektron_sample_header;
810 GByteArray *msg = elektron_new_msg (FS_SAMPLE_WRITE_FILE_REQUEST,
811 sizeof (FS_SAMPLE_WRITE_FILE_REQUEST));
812
813
814 aux32 = htobe32 (id);
815 memcpy (&msg->data[5], &aux32, sizeof (guint32));
816 aux32 = htobe32 (DATA_TRANSF_BLOCK_BYTES * seq);
817 memcpy (&msg->data[13], &aux32, sizeof (guint32));
818
819 bytes_blk = DATA_TRANSF_BLOCK_BYTES;
820 consumed = 0;
821
822 if (seq == 0)
823 {
824 elektron_sample_header.type = 0;
825 elektron_sample_header.sample_len_bytes = htobe32 (sample->len);
826 elektron_sample_header.samplerate = htobe32 (ELEKTRON_SAMPLE_RATE);
827 elektron_sample_header.loopstart = htobe32 (sample_info->loopstart);
828 elektron_sample_header.loopend = htobe32 (sample_info->loopend);
829 elektron_sample_header.looptype = htobe32 (ELEKTRON_LOOP_TYPE);
830 memset (&elektron_sample_header.padding, 0,
831 sizeof (guint32) * ELEKTRON_SAMPLE_INFO_PAD_I32_LEN);
832
833 g_byte_array_append (msg, (guchar *) & elektron_sample_header,
834 sizeof (struct elektron_sample_header));
835
836 consumed = sizeof (struct elektron_sample_header);
837 bytes_blk -= consumed;
838 }
839
840 i = 0;
841 aux16p = (guint16 *) & sample->data[*total];
842 while (i < bytes_blk && *total < sample->len)
843 {
844 aux16 = htobe16 (*aux16p);
845 g_byte_array_append (msg, (guint8 *) & aux16, sizeof (guint16));
846 aux16p++;
847 (*total) += sizeof (guint16);
848 consumed += sizeof (guint16);
849 i += sizeof (guint16);
850 }
851
852 aux32 = htobe32 (consumed);
853 memcpy (&msg->data[9], &aux32, sizeof (guint32));
854
855 return msg;
856 }
857
858 static GByteArray *
859 elektron_new_msg_write_raw_blk (guint id, GByteArray * raw, guint * total,
860 guint seq, void *data)
861 {
862 gint len;
863 guint32 aux32;
864 GByteArray *msg = elektron_new_msg (FS_RAW_WRITE_FILE_REQUEST,
865 sizeof (FS_RAW_WRITE_FILE_REQUEST));
866
867 aux32 = htobe32 (id);
868 memcpy (&msg->data[5], &aux32, sizeof (guint32));
869 aux32 = htobe32 (DATA_TRANSF_BLOCK_BYTES * seq);
870 memcpy (&msg->data[13], &aux32, sizeof (guint32));
871
872 len = raw->len - *total;
873 len = len > DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : len;
874 g_byte_array_append (msg, &raw->data[*total], len);
875 (*total) += len;
876
877 aux32 = htobe32 (len);
878 memcpy (&msg->data[9], &aux32, sizeof (guint32));
879
880 return msg;
881 }
882
883 static GByteArray *
884 elektron_new_msg_close_common_write (const guint8 * data, guint len,
885 guint id, guint bytes)
886 {
887 guint32 aux32;
888 GByteArray *msg = elektron_new_msg (data, len);
889
890 aux32 = htobe32 (id);
891 memcpy (&msg->data[5], &aux32, sizeof (guint32));
892 aux32 = htobe32 (bytes);
893 memcpy (&msg->data[9], &aux32, sizeof (guint32));
894
895 return msg;
896 }
897
898 static GByteArray *
899 elektron_new_msg_close_sample_write (guint id, guint bytes)
900 {
901 return
902 elektron_new_msg_close_common_write (FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST,
903 sizeof
904 (FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST),
905 id,
906 bytes +
907 sizeof (struct
908 elektron_sample_header));
909 }
910
911 static GByteArray *
912 elektron_new_msg_close_raw_write (guint id, guint bytes)
913 {
914 return
915 elektron_new_msg_close_common_write (FS_RAW_CLOSE_FILE_WRITER_REQUEST,
916 sizeof
917 (FS_RAW_CLOSE_FILE_WRITER_REQUEST),
918 id, bytes);
919 }
920
921 static GByteArray *
922 elektron_new_msg_read_common_blk (const guint8 * data, guint len, guint id,
923 guint start, guint size)
924 {
925 guint32 aux;
926 GByteArray *msg = elektron_new_msg (data, len);
927
928 aux = htobe32 (id);
929 memcpy (&msg->data[5], &aux, sizeof (guint32));
930 aux = htobe32 (size);
931 memcpy (&msg->data[9], &aux, sizeof (guint32));
932 aux = htobe32 (start);
933 memcpy (&msg->data[13], &aux, sizeof (guint32));
934
935 return msg;
936 }
937
938 static GByteArray *
939 elektron_new_msg_read_sample_blk (guint id, guint start, guint size)
940 {
941 return elektron_new_msg_read_common_blk (FS_SAMPLE_READ_FILE_REQUEST,
942 sizeof
943 (FS_SAMPLE_READ_FILE_REQUEST), id,
944 start, size);
945 }
946
947 static GByteArray *
948 elektron_new_msg_read_raw_blk (guint id, guint start, guint size)
949 {
950 return elektron_new_msg_read_common_blk (FS_RAW_READ_FILE_REQUEST,
951 sizeof (FS_RAW_READ_FILE_REQUEST),
952 id, start, size);
953 }
954
955 static GByteArray *
956 elektron_raw_to_msg (GByteArray * sysex)
957 {
958 GByteArray *msg;
959 GByteArray *payload;
960 gint len = sysex->len - sizeof (MSG_HEADER) - 1;
961
962 if (len > 0)
963 {
964 payload = g_byte_array_new ();
965 g_byte_array_append (payload, &sysex->data[sizeof (MSG_HEADER)], len);
966 msg = elektron_decode_payload (payload);
967 free_msg (payload);
968 }
969 else
970 {
971 msg = NULL;
972 }
973
974 return msg;
975 }
976
977 static gint
978 elektron_tx (struct backend *backend, const GByteArray * msg)
979 {
980 gint res;
981 guint16 aux;
982 gchar *text;
983 struct sysex_transfer transfer;
984 struct elektron_data *data = backend->data;
985
986 aux = htobe16 (data->seq);
987 memcpy (msg->data, &aux, sizeof (guint16));
988 data->seq++;
989
990 transfer.raw = elektron_msg_to_raw (msg);
991 res = backend_tx_sysex (backend, &transfer);
992 if (!res)
993 {
994 text = debug_get_hex_msg (msg);
995 debug_print (1, "Message sent (%d): %s\n", msg->len, text);
996 free (text);
997 }
998
999 free_msg (transfer.raw);
1000 return res;
1001 }
1002
1003 static GByteArray *
1004 elektron_rx (struct backend *backend, gint timeout)
1005 {
1006 gchar *text;
1007 GByteArray *msg;
1008 struct sysex_transfer transfer;
1009
1010 transfer.timeout = timeout;
1011 transfer.batch = FALSE;
1012
1013 while (1)
1014 {
1015 if (backend_rx_sysex (backend, &transfer))
1016 {
1017 return NULL;
1018 }
1019
1020 if (transfer.raw->len >= 12
1021 && !memcmp (transfer.raw->data, MSG_HEADER, 6))
1022 {
1023 break;
1024 }
1025
1026 if (debug_level > 1)
1027 {
1028 text = debug_get_hex_msg (transfer.raw);
1029 debug_print (2, "Message skipped (%d): %s\n", transfer.raw->len,
1030 text);
1031 free (text);
1032 }
1033 free_msg (transfer.raw);
1034 }
1035
1036 msg = elektron_raw_to_msg (transfer.raw);
1037 if (msg)
1038 {
1039 text = debug_get_hex_msg (msg);
1040 debug_print (1, "Message received (%d): %s\n", msg->len, text);
1041 free (text);
1042 }
1043
1044 free_msg (transfer.raw);
1045 return msg;
1046 }
1047
1048 //Not synchronized. Only meant to be called from elektron_tx_and_rx_timeout.
1049
1050 static GByteArray *
1051 elektron_tx_and_rx_timeout_no_cache (struct backend *backend,
1052 GByteArray * tx_msg, gint timeout)
1053 {
1054 ssize_t len;
1055 GByteArray *rx_msg;
1056 guint msg_type = tx_msg->data[4] | 0x80;
1057
1058 len = elektron_tx (backend, tx_msg);
1059 if (len < 0)
1060 {
1061 rx_msg = NULL;
1062 goto cleanup;
1063 }
1064
1065 rx_msg = elektron_rx (backend, timeout < 0 ? BE_SYSEX_TIMEOUT_MS : timeout);
1066 if (rx_msg && rx_msg->data[4] != msg_type)
1067 {
1068 error_print ("Illegal message type in response\n");
1069 free_msg (rx_msg);
1070 rx_msg = NULL;
1071 goto cleanup;
1072 }
1073
1074 cleanup:
1075 free_msg (tx_msg);
1076 return rx_msg;
1077 }
1078
1079 //Synchronized
1080
1081 static GByteArray *
1082 elektron_tx_and_rx_timeout (struct backend *backend, GByteArray * tx_msg,
1083 gint timeout)
1084 {
1085 GBytes *key;
1086 GByteArray *rx_msg, *ret = NULL;
1087
1088 g_mutex_lock (&backend->mutex);
1089 if (backend->cache)
1090 {
1091 key = g_bytes_new (tx_msg->data, tx_msg->len);
1092 rx_msg = g_hash_table_lookup (backend->cache, key);
1093 if (rx_msg)
1094 {
1095 ret = g_byte_array_sized_new (rx_msg->len);
1096 g_byte_array_append (ret, rx_msg->data, rx_msg->len);
1097 g_bytes_unref (key);
1098 goto end;
1099 }
1100
1101 rx_msg = elektron_tx_and_rx_timeout_no_cache (backend, tx_msg, timeout);
1102 if (!rx_msg)
1103 {
1104 g_bytes_unref (key);
1105 goto end;
1106 }
1107
1108 ret = g_byte_array_sized_new (rx_msg->len);
1109 g_byte_array_append (ret, rx_msg->data, rx_msg->len);
1110 g_hash_table_insert (backend->cache, key, rx_msg);
1111 }
1112 else
1113 {
1114 ret = elektron_tx_and_rx_timeout_no_cache (backend, tx_msg, timeout);
1115 }
1116
1117 end:
1118 g_mutex_unlock (&backend->mutex);
1119 return ret;
1120 }
1121
1122 static GByteArray *
1123 elektron_tx_and_rx (struct backend *backend, GByteArray * tx_msg)
1124 {
1125 return elektron_tx_and_rx_timeout (backend, tx_msg, -1);
1126 }
1127
1128 static enum item_type
1129 elektron_get_path_type (struct backend *backend, const gchar * path,
1130 fs_init_iter_func init_iter)
1131 {
1132 gchar *name_copy;
1133 gchar *parent_copy;
1134 gchar *name;
1135 gchar *parent;
1136 enum item_type res;
1137 struct item_iterator iter;
1138
1139 if (strcmp (path, "/") == 0)
1140 {
1141 return ELEKTROID_DIR;
1142 }
1143
1144 name_copy = strdup (path);
1145 parent_copy = strdup (path);
1146 name = basename (name_copy);
1147 parent = dirname (parent_copy);
1148 res = ELEKTROID_NONE;
1149 if (!init_iter (backend, &iter, parent))
1150 {
1151 while (!next_item_iterator (&iter))
1152 {
1153 if (strcmp (name, iter.item.name) == 0)
1154 {
1155 res = iter.item.type;
1156 break;
1157 }
1158 }
1159 free_item_iterator (&iter);
1160 }
1161
1162 g_free (name_copy);
1163 g_free (parent_copy);
1164 return res;
1165 }
1166
1167 static gint
1168 elektron_read_common_dir (struct backend *backend,
1169 struct item_iterator *iter, const gchar * dir,
1170 const guint8 msg[], int size,
1171 fs_init_iter_func init_iter, enum elektron_fs fs)
1172 {
1173 gboolean cache = FALSE;
1174 GByteArray *tx_msg, *rx_msg = NULL;
1175
1176 tx_msg = elektron_new_msg_path (msg, size, dir);
1177 if (!tx_msg)
1178 {
1179 return -EINVAL;
1180 }
1181
1182 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1183 if (!rx_msg)
1184 {
1185 return -EIO;
1186 }
1187
1188 if (rx_msg->len == 5 &&
1189 elektron_get_path_type (backend, dir, init_iter) != ELEKTROID_DIR)
1190 {
1191 free_msg (rx_msg);
1192 return -ENOTDIR;
1193 }
1194
1195 return elektron_init_iterator (iter, rx_msg, elektron_next_smplrw_entry,
1196 fs, cache);
1197 }
1198
1199 static gint
1200 elektron_read_samples_dir (struct backend *backend,
1201 struct item_iterator *iter, const gchar * dir)
1202 {
1203 return elektron_read_common_dir (backend, iter, dir,
1204 FS_SAMPLE_READ_DIR_REQUEST,
1205 sizeof (FS_SAMPLE_READ_DIR_REQUEST),
1206 elektron_read_samples_dir, FS_SAMPLES);
1207 }
1208
1209 static gint
1210 elektron_read_raw_dir (struct backend *backend, struct item_iterator *iter,
1211 const gchar * dir)
1212 {
1213 return elektron_read_common_dir (backend, iter, dir,
1214 FS_RAW_READ_DIR_REQUEST,
1215 sizeof (FS_RAW_READ_DIR_REQUEST),
1216 elektron_read_raw_dir, FS_RAW_ALL);
1217 }
1218
1219 static gint
1220 elektron_src_dst_common (struct backend *backend,
1221 const gchar * src, const gchar * dst,
1222 const guint8 * data, guint len)
1223 {
1224 gint res;
1225 GByteArray *rx_msg;
1226 GByteArray *tx_msg = elektron_new_msg (data, len);
1227
1228 gchar *dst_cp1252 = elektron_get_cp1252 (dst);
1229 if (!dst_cp1252)
1230 {
1231 return -EINVAL;
1232 }
1233
1234 gchar *src_cp1252 = elektron_get_cp1252 (src);
1235 if (!src_cp1252)
1236 {
1237 g_free (dst_cp1252);
1238 return -EINVAL;
1239 }
1240
1241 g_byte_array_append (tx_msg, (guchar *) src_cp1252,
1242 strlen (src_cp1252) + 1);
1243 g_byte_array_append (tx_msg, (guchar *) dst_cp1252,
1244 strlen (dst_cp1252) + 1);
1245
1246 g_free (src_cp1252);
1247 g_free (dst_cp1252);
1248
1249 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1250 if (!rx_msg)
1251 {
1252 return -EIO;
1253 }
1254 //Response: x, x, x, x, 0xa1, [0 (error), 1 (success)]...
1255 if (elektron_get_msg_status (rx_msg))
1256 {
1257 res = 0;
1258 }
1259 else
1260 {
1261 res = -EPERM;
1262 error_print ("%s (%s)\n", snd_strerror (res),
1263 elektron_get_msg_string (rx_msg));
1264 }
1265 free_msg (rx_msg);
1266
1267 return res;
1268 }
1269
1270 static gint
1271 elektron_rename_sample_file (struct backend *backend, const gchar * src,
1272 const gchar * dst)
1273 {
1274 return elektron_src_dst_common (backend, src, dst,
1275 FS_SAMPLE_RENAME_FILE_REQUEST,
1276 sizeof (FS_SAMPLE_RENAME_FILE_REQUEST));
1277 }
1278
1279 static gint
1280 elektron_rename_raw_file (struct backend *backend, const gchar * src,
1281 const gchar * dst)
1282 {
1283 return elektron_src_dst_common (backend, src, dst,
1284 FS_RAW_RENAME_FILE_REQUEST,
1285 sizeof (FS_RAW_RENAME_FILE_REQUEST));
1286 }
1287
1288 static gint
1289 elektron_move_common_item (struct backend *backend, const gchar * src,
1290 const gchar * dst, fs_init_iter_func init_iter,
1291 elektron_src_dst_func mv, fs_path_func mkdir,
1292 elektron_path_func rmdir)
1293 {
1294 enum item_type type;
1295 gint res;
1296 gchar *src_plus;
1297 gchar *dst_plus;
1298 struct item_iterator iter;
1299
1300 //Renaming is not implemented for directories so we need to implement it.
1301
1302 debug_print (1, "Renaming remotely from %s to %s...\n", src, dst);
1303
1304 type = elektron_get_path_type (backend, src, init_iter);
1305 if (type == ELEKTROID_FILE)
1306 {
1307 return mv (backend, src, dst);
1308 }
1309 else if (type == ELEKTROID_DIR)
1310 {
1311 res = mkdir (backend, dst);
1312 if (res)
1313 {
1314 return res;
1315 }
1316 if (!init_iter (backend, &iter, src))
1317 {
1318 while (!next_item_iterator (&iter) && !res)
1319 {
1320 src_plus = chain_path (src, iter.item.name);
1321 dst_plus = chain_path (dst, iter.item.name);
1322 res = elektron_move_common_item (backend, src_plus, dst_plus,
1323 init_iter, mv, mkdir, rmdir);
1324 free (src_plus);
1325 free (dst_plus);
1326 }
1327 free_item_iterator (&iter);
1328 }
1329 if (!res)
1330 {
1331 res = rmdir (backend, src);
1332 }
1333 return res;
1334 }
1335 else
1336 {
1337 return -EBADF;
1338 }
1339 }
1340
1341 static gint
1342 elektron_path_common (struct backend *backend, const gchar * path,
1343 const guint8 * template, gint size)
1344 {
1345 gint res;
1346 GByteArray *rx_msg;
1347 GByteArray *tx_msg;
1348
1349 tx_msg = elektron_new_msg_path (template, size, path);
1350 if (!tx_msg)
1351 {
1352 return -EINVAL;
1353 }
1354
1355 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1356 if (!rx_msg)
1357 {
1358 return -EIO;
1359 }
1360 //Response: x, x, x, x, 0xX0, [0 (error), 1 (success)]...
1361 if (elektron_get_msg_status (rx_msg))
1362 {
1363 res = 0;
1364 }
1365 else
1366 {
1367 res = -EPERM;
1368 error_print ("%s (%s)\n", snd_strerror (res),
1369 elektron_get_msg_string (rx_msg));
1370 }
1371 free_msg (rx_msg);
1372
1373 return res;
1374 }
1375
1376 static gint
1377 elektron_delete_sample (struct backend *backend, const gchar * path)
1378 {
1379 return elektron_path_common (backend, path,
1380 FS_SAMPLE_DELETE_FILE_REQUEST,
1381 sizeof (FS_SAMPLE_DELETE_FILE_REQUEST));
1382 }
1383
1384 static gint
1385 elektron_delete_samples_dir (struct backend *backend, const gchar * path)
1386 {
1387 return elektron_path_common (backend, path, FS_SAMPLE_DELETE_DIR_REQUEST,
1388 sizeof (FS_SAMPLE_DELETE_DIR_REQUEST));
1389 }
1390
1391 //This adds back the extension ".mc-snd" that the device provides.
1392 static gchar *
1393 elektron_add_ext_to_mc_snd (const gchar * path)
1394 {
1395 gchar *path_with_ext = malloc (PATH_MAX);
1396 snprintf (path_with_ext, PATH_MAX, "%s%s", path, ".mc-snd");
1397 return path_with_ext;
1398 }
1399
1400 static gint
1401 elektron_delete_raw (struct backend *backend, const gchar * path)
1402 {
1403 gint ret;
1404 gchar *path_with_ext = elektron_add_ext_to_mc_snd (path);
1405 ret = elektron_path_common (backend, path_with_ext,
1406 FS_RAW_DELETE_FILE_REQUEST,
1407 sizeof (FS_RAW_DELETE_FILE_REQUEST));
1408 g_free (path_with_ext);
1409 return ret;
1410 }
1411
1412 static gint
1413 elektron_delete_raw_dir (struct backend *backend, const gchar * path)
1414 {
1415 return elektron_path_common (backend, path, FS_RAW_DELETE_DIR_REQUEST,
1416 sizeof (FS_RAW_DELETE_DIR_REQUEST));
1417 }
1418
1419 static gint
1420 elektron_create_samples_dir (struct backend *backend, const gchar * path)
1421 {
1422 return elektron_path_common (backend, path, FS_SAMPLE_CREATE_DIR_REQUEST,
1423 sizeof (FS_SAMPLE_CREATE_DIR_REQUEST));
1424 }
1425
1426 static gint
1427 elektron_move_samples_item (struct backend *backend, const gchar * src,
1428 const gchar * dst)
1429 {
1430 return elektron_move_common_item (backend, src, dst,
1431 elektron_read_samples_dir,
1432 elektron_rename_sample_file,
1433 elektron_create_samples_dir,
1434 elektron_delete_samples_dir);
1435 }
1436
1437 static gint
1438 elektron_create_raw_dir (struct backend *backend, const gchar * path)
1439 {
1440 return elektron_path_common (backend, path, FS_RAW_CREATE_DIR_REQUEST,
1441 sizeof (FS_RAW_CREATE_DIR_REQUEST));
1442 }
1443
1444 static gint
1445 elektron_move_raw_item (struct backend *backend, const gchar * src,
1446 const gchar * dst)
1447 {
1448 gint ret;
1449 gchar *src_with_ext = elektron_add_ext_to_mc_snd (src);
1450 ret = elektron_move_common_item (backend, src_with_ext, dst,
1451 elektron_read_raw_dir,
1452 elektron_rename_raw_file,
1453 elektron_create_raw_dir,
1454 elektron_delete_raw_dir);
1455 g_free (src_with_ext);
1456 return ret;
1457 }
1458
1459 static gint
1460 elektron_delete_common_item (struct backend *backend, const gchar * path,
1461 fs_init_iter_func init_iter,
1462 elektron_path_func rmdir, elektron_path_func rm)
1463 {
1464 enum item_type type;
1465 gchar *new_path;
1466 struct item_iterator iter;
1467 gint res;
1468
1469 type = elektron_get_path_type (backend, path, init_iter);
1470 if (type == ELEKTROID_FILE)
1471 {
1472 return rm (backend, path);
1473 }
1474 else if (type == ELEKTROID_DIR)
1475 {
1476 debug_print (1, "Deleting %s samples dir...\n", path);
1477
1478 if (init_iter (backend, &iter, path))
1479 {
1480 error_print ("Error while opening samples dir %s dir\n", path);
1481 res = -EINVAL;
1482 }
1483 else
1484 {
1485 res = 0;
1486 while (!res && !next_item_iterator (&iter))
1487 {
1488 new_path = chain_path (path, iter.item.name);
1489 res = res
1490 || elektron_delete_common_item (backend, new_path,
1491 init_iter, rmdir, rm);
1492 free (new_path);
1493 }
1494 free_item_iterator (&iter);
1495 }
1496 return res || rmdir (backend, path);
1497 }
1498 else
1499 {
1500 return -EBADF;
1501 }
1502 }
1503
1504 static gint
1505 elektron_delete_samples_item (struct backend *backend, const gchar * path)
1506 {
1507 return elektron_delete_common_item (backend, path,
1508 elektron_read_samples_dir,
1509 elektron_delete_samples_dir,
1510 elektron_delete_sample);
1511 }
1512
1513 static gint
1514 elektron_delete_raw_item (struct backend *backend, const gchar * path)
1515 {
1516 return elektron_delete_common_item (backend, path,
1517 elektron_read_raw_dir,
1518 elektron_delete_raw_dir,
1519 elektron_delete_raw);
1520 }
1521
1522 static gint
1523 elektron_upload_smplrw (struct backend *backend, const gchar * path,
1524 GByteArray * input, struct job_control *control,
1525 elektron_msg_path_len_func new_msg_open_write,
1526 elektron_msg_write_blk_func new_msg_write_blk,
1527 elektron_msg_id_len_func new_msg_close_write)
1528 {
1529 GByteArray *tx_msg;
1530 GByteArray *rx_msg;
1531 guint transferred;
1532 guint32 id;
1533 int i;
1534 gboolean active;
1535 gint res = 0;
1536
1537 //If the file already exists the device makes no difference between creating a new file and creating an already existent file.
1538 //Also, the new file would be discarded if an upload is not completed.
1539
1540 tx_msg = new_msg_open_write (path, input->len);
1541 if (!tx_msg)
1542 {
1543 return -EINVAL;
1544 }
1545
1546 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1547 if (!rx_msg)
1548 {
1549 return -EIO;
1550 }
1551
1552 //Response: x, x, x, x, 0xc0, [0 (error), 1 (success)], id, frames
1553 res = elektron_get_smplrw_info_from_msg (rx_msg, &id, NULL);
1554 if (res)
1555 {
1556 error_print ("%s (%s)\n", snd_strerror (res),
1557 elektron_get_msg_string (rx_msg));
1558 free_msg (rx_msg);
1559 return res;
1560 }
1561 free_msg (rx_msg);
1562
1563 transferred = 0;
1564 i = 0;
1565
1566 g_mutex_lock (&control->mutex);
1567 active = control->active;
1568 g_mutex_unlock (&control->mutex);
1569
1570 while (transferred < input->len && active)
1571 {
1572 tx_msg = new_msg_write_blk (id, input, &transferred, i, control->data);
1573 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1574 if (!rx_msg)
1575 {
1576 return -EIO;
1577 }
1578 //Response: x, x, x, x, 0xc2, [0 (error), 1 (success)]...
1579 if (!elektron_get_msg_status (rx_msg))
1580 {
1581 error_print ("Unexpected status\n");
1582 }
1583 free_msg (rx_msg);
1584 i++;
1585
1586 set_job_control_progress (control, transferred / (double) input->len);
1587 g_mutex_lock (&control->mutex);
1588 active = control->active;
1589 g_mutex_unlock (&control->mutex);
1590
1591 usleep (BE_REST_TIME_US);
1592 }
1593
1594 debug_print (2, "%d bytes sent\n", transferred);
1595
1596 if (active)
1597 {
1598 tx_msg = new_msg_close_write (id, transferred);
1599 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1600 if (!rx_msg)
1601 {
1602 return -EIO;
1603 }
1604 //Response: x, x, x, x, 0xc1, [0 (error), 1 (success)]...
1605 if (!elektron_get_msg_status (rx_msg))
1606 {
1607 error_print ("Unexpected status\n");
1608 }
1609 free_msg (rx_msg);
1610 }
1611
1612 return res;
1613 }
1614
1615 static gint
1616 elektron_upload_sample_part (struct backend *backend, const gchar * path,
1617 GByteArray * sample, struct job_control *control)
1618 {
1619 return elektron_upload_smplrw (backend, path, sample, control,
1620 elektron_new_msg_open_sample_write,
1621 elektron_new_msg_write_sample_blk,
1622 elektron_new_msg_close_sample_write);
1623 }
1624
1625 static gint
1626 elektron_upload_sample (struct backend *backend, const gchar * path,
1627 GByteArray * input, struct job_control *control)
1628 {
1629 control->parts = 1;
1630 control->part = 0;
1631 return elektron_upload_sample_part (backend, path, input, control);
1632 }
1633
1634 static gint
1635 elektron_upload_raw (struct backend *backend, const gchar * path,
1636 GByteArray * sample, struct job_control *control)
1637 {
1638 return elektron_upload_smplrw (backend, path, sample, control,
1639 elektron_new_msg_open_raw_write,
1640 elektron_new_msg_write_raw_blk,
1641 elektron_new_msg_close_raw_write);
1642 }
1643
1644 static GByteArray *
1645 elektron_new_msg_open_sample_read (const gchar * path)
1646 {
1647 return elektron_new_msg_path (FS_SAMPLE_OPEN_FILE_READER_REQUEST,
1648 sizeof
1649 (FS_SAMPLE_OPEN_FILE_READER_REQUEST), path);
1650 }
1651
1652 static GByteArray *
1653 elektron_new_msg_open_raw_read (const gchar * path)
1654 {
1655 return elektron_new_msg_path (FS_RAW_OPEN_FILE_READER_REQUEST,
1656 sizeof
1657 (FS_RAW_OPEN_FILE_READER_REQUEST), path);
1658 }
1659
1660 static void
1661 elektron_copy_sample_data (GByteArray * input, GByteArray * output)
1662 {
1663 gint i;
1664 gint16 v;
1665 gint16 *frame = (gint16 *) input->data;
1666
1667 for (i = 0; i < input->len; i += sizeof (gint16))
1668 {
1669 v = be16toh (*frame);
1670 g_byte_array_append (output, (guint8 *) & v, sizeof (gint16));
1671 frame++;
1672 }
1673 }
1674
1675 static void
1676 elektron_copy_raw_data (GByteArray * input, GByteArray * output)
1677 {
1678 g_byte_array_append (output, input->data, input->len);
1679 }
1680
1681 static gint
1682 elektron_download_smplrw (struct backend *backend, const gchar * path,
1683 GByteArray * output, struct job_control *control,
1684 elektron_msg_path_func new_msg_open_read,
1685 guint read_offset,
1686 elektron_msg_read_blk_func new_msg_read_blk,
1687 elektron_msg_id_func new_msg_close_read,
1688 elektron_copy_array copy_array)
1689 {
1690 struct sample_info *sample_info;
1691 struct elektron_sample_header *elektron_sample_header;
1692 GByteArray *tx_msg;
1693 GByteArray *rx_msg;
1694 GByteArray *array;
1695 guint32 id;
1696 guint frames;
1697 guint next_block_start;
1698 guint req_size;
1699 guint offset;
1700 gboolean active;
1701 gint res;
1702
1703 tx_msg = new_msg_open_read (path);
1704 if (!tx_msg)
1705 {
1706 return -EINVAL;
1707 }
1708
1709 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1710 if (!rx_msg)
1711 {
1712 return -EIO;
1713 }
1714 res = elektron_get_smplrw_info_from_msg (rx_msg, &id, &frames);
1715 if (res)
1716 {
1717 error_print ("%s (%s)\n", snd_strerror (res),
1718 elektron_get_msg_string (rx_msg));
1719 free_msg (rx_msg);
1720 return res;
1721 }
1722 free_msg (rx_msg);
1723
1724 debug_print (2, "%d frames to download\n", frames);
1725
1726 g_mutex_lock (&control->mutex);
1727 active = control->active;
1728 g_mutex_unlock (&control->mutex);
1729
1730 array = g_byte_array_new ();
1731 res = 0;
1732 next_block_start = 0;
1733 offset = read_offset;
1734 control->data = NULL;
1735 while (next_block_start < frames && active)
1736 {
1737 req_size =
1738 frames - next_block_start >
1739 DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : frames -
1740 next_block_start;
1741 tx_msg = new_msg_read_blk (id, next_block_start, req_size);
1742 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1743 if (!rx_msg)
1744 {
1745 res = -EIO;
1746 goto cleanup;
1747 }
1748 g_byte_array_append (array, &rx_msg->data[FS_SAMPLES_PAD_RES + offset],
1749 req_size - offset);
1750
1751 next_block_start += req_size;
1752 //Only in the first iteration. It has no effect for the raw filesystem (M:C) as offset is 0.
1753 if (offset)
1754 {
1755 offset = 0;
1756 elektron_sample_header =
1757 (struct elektron_sample_header *)
1758 &rx_msg->data[FS_SAMPLES_PAD_RES];
1759 sample_info = malloc (sizeof (struct elektron_sample_header));
1760 sample_info->loopstart =
1761 be32toh (elektron_sample_header->loopstart);
1762 sample_info->loopend = be32toh (elektron_sample_header->loopend);
1763 sample_info->looptype = be32toh (elektron_sample_header->looptype);
1764 sample_info->samplerate = be32toh (elektron_sample_header->samplerate); //In the case of the RAW filesystem is not used and it is harmless.
1765 sample_info->channels = 1;
1766 sample_info->bitdepth = 16;
1767 control->data = sample_info;
1768 debug_print (2, "Loop start at %d, loop end at %d\n",
1769 sample_info->loopstart, sample_info->loopend);
1770 }
1771
1772 free_msg (rx_msg);
1773
1774 set_job_control_progress (control, next_block_start / (double) frames);
1775 g_mutex_lock (&control->mutex);
1776 active = control->active;
1777 g_mutex_unlock (&control->mutex);
1778
1779 usleep (BE_REST_TIME_US);
1780 }
1781
1782 debug_print (2, "%d bytes received\n", next_block_start);
1783
1784 if (active)
1785 {
1786 copy_array (array, output);
1787 }
1788 else
1789 {
1790 res = -1;
1791 }
1792
1793 tx_msg = new_msg_close_read (id);
1794 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1795 if (!rx_msg)
1796 {
1797 res = -EIO;
1798 goto cleanup;
1799 }
1800 //Response: x, x, x, x, 0xb1, 00 00 00 0a 00 01 65 de (sample id and received bytes)
1801 free_msg (rx_msg);
1802
1803 cleanup:
1804 free_msg (array);
1805 if (res)
1806 {
1807 g_free (control->data);
1808 }
1809 return res;
1810 }
1811
1812 static gint
1813 elektron_download_sample_part (struct backend *backend, const gchar * path,
1814 GByteArray * output,
1815 struct job_control *control)
1816 {
1817 return elektron_download_smplrw (backend, path, output, control,
1818 elektron_new_msg_open_sample_read,
1819 sizeof (struct elektron_sample_header),
1820 elektron_new_msg_read_sample_blk,
1821 elektron_new_msg_close_sample_read,
1822 elektron_copy_sample_data);
1823 }
1824
1825 static gint
1826 elektron_download_sample (struct backend *backend, const gchar * path,
1827 GByteArray * output, struct job_control *control)
1828 {
1829 control->parts = 1;
1830 control->part = 0;
1831 return elektron_download_sample_part (backend, path, output, control);
1832 }
1833
1834 static gint
1835 elektron_download_raw (struct backend *backend, const gchar * path,
1836 GByteArray * output, struct job_control *control)
1837 {
1838 gint ret;
1839 gchar *path_with_ext = elektron_add_ext_to_mc_snd (path);
1840 ret = elektron_download_smplrw (backend, path_with_ext, output, control,
1841 elektron_new_msg_open_raw_read,
1842 0, elektron_new_msg_read_raw_blk,
1843 elektron_new_msg_close_raw_read,
1844 elektron_copy_raw_data);
1845 g_free (path_with_ext);
1846 return ret;
1847 }
1848
1849 static GByteArray *
1850 elektron_new_msg_upgrade_os_start (guint size)
1851 {
1852 GByteArray *msg = elektron_new_msg (OS_UPGRADE_START_REQUEST,
1853 sizeof (OS_UPGRADE_START_REQUEST));
1854
1855 memcpy (&msg->data[5], &size, sizeof (guint32));
1856
1857 return msg;
1858 }
1859
1860 static GByteArray *
1861 elektron_new_msg_upgrade_os_write (GByteArray * os_data, gint * offset)
1862 {
1863 GByteArray *msg = elektron_new_msg (OS_UPGRADE_WRITE_RESPONSE,
1864 sizeof (OS_UPGRADE_WRITE_RESPONSE));
1865 guint len;
1866 guint32 crc;
1867 guint32 aux32;
1868
1869 if (*offset + OS_TRANSF_BLOCK_BYTES < os_data->len)
1870 {
1871 len = OS_TRANSF_BLOCK_BYTES;
1872 }
1873 else
1874 {
1875 len = os_data->len - *offset;
1876 }
1877
1878 crc = crc32 (0xffffffff, &os_data->data[*offset], len);
1879
1880 debug_print (2, "CRC: %0x\n", crc);
1881
1882 aux32 = htobe32 (crc);
1883 memcpy (&msg->data[5], &aux32, sizeof (guint32));
1884 aux32 = htobe32 (len);
1885 memcpy (&msg->data[9], &aux32, sizeof (guint32));
1886 aux32 = htobe32 (*offset);
1887 memcpy (&msg->data[13], &aux32, sizeof (guint32));
1888
1889 g_byte_array_append (msg, &os_data->data[*offset], len);
1890
1891 *offset = *offset + len;
1892
1893 return msg;
1894 }
1895
1896 static gint
1897 elektron_upgrade_os (struct backend *backend, struct sysex_transfer *transfer)
1898 {
1899 GByteArray *tx_msg;
1900 GByteArray *rx_msg;
1901 gint8 op;
1902 gint offset;
1903 gint res = 0;
1904
1905 tx_msg = elektron_new_msg_upgrade_os_start (transfer->raw->len);
1906 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1907
1908 if (!rx_msg)
1909 {
1910 res = -EIO;
1911 goto end;
1912 }
1913 //Response: x, x, x, x, 0xd0, [0 (ok), 1 (error)]...
1914 op = elektron_get_msg_status (rx_msg);
1915 if (op)
1916 {
1917 res = -EIO;
1918 error_print ("%s (%s)\n", snd_strerror (res),
1919 elektron_get_msg_string (rx_msg));
1920 free_msg (rx_msg);
1921 goto end;
1922 }
1923
1924 free_msg (rx_msg);
1925
1926 offset = 0;
1927 while (offset < transfer->raw->len)
1928 {
1929 tx_msg = elektron_new_msg_upgrade_os_write (transfer->raw, &offset);
1930 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1931
1932 if (!rx_msg)
1933 {
1934 res = -EIO;
1935 break;
1936 }
1937 //Response: x, x, x, x, 0xd1, int32, [0..3]...
1938 op = rx_msg->data[9];
1939 if (op == 1)
1940 {
1941 break;
1942 }
1943 else if (op > 1)
1944 {
1945 res = -EIO;
1946 error_print ("%s (%s)\n", snd_strerror (res),
1947 elektron_get_msg_string (rx_msg));
1948 free_msg (rx_msg);
1949 break;
1950 }
1951
1952 free_msg (rx_msg);
1953
1954 usleep (BE_REST_TIME_US);
1955 }
1956
1957 end:
1958 return res;
1959 }
1960
1961 static gint
1962 elektron_get_storage_stats (struct backend *backend, gint type,
1963 struct backend_storage_stats *statfs)
1964 {
1965 GByteArray *tx_msg, *rx_msg;
1966 gint8 op;
1967 guint64 *data;
1968 int index;
1969 gint res = 0;
1970
1971 tx_msg = elektron_new_msg_uint8 (STORAGEINFO_REQUEST,
1972 sizeof (STORAGEINFO_REQUEST), type);
1973 rx_msg = elektron_tx_and_rx (backend, tx_msg);
1974 if (!rx_msg)
1975 {
1976 return -EIO;
1977 }
1978
1979 op = elektron_get_msg_status (rx_msg);
1980 if (!op)
1981 {
1982 error_print ("%s (%s)\n", snd_strerror (-EIO),
1983 elektron_get_msg_string (rx_msg));
1984 free_msg (rx_msg);
1985 return -EIO;
1986 }
1987
1988 index = 0;
1989 for (int i = 0, storage = STORAGE_PLUS_DRIVE; storage <= STORAGE_RAM;
1990 i++, storage <<= 1)
1991 {
1992 if (storage == type)
1993 {
1994 index = i;
1995 }
1996 }
1997
1998 statfs->name = FS_TYPE_NAMES[index];
1999 data = (guint64 *) & rx_msg->data[6];
2000 statfs->bfree = be64toh (*data);
2001 data = (guint64 *) & rx_msg->data[14];
2002 statfs->bsize = be64toh (*data);
2003
2004 free_msg (rx_msg);
2005
2006 return res;
2007 }
2008
2009 gint
2010 elektron_load_device_desc (struct device_desc *device_desc, guint8 id)
2011 {
2012 gint err, devices;
2013 JsonParser *parser;
2014 JsonReader *reader;
2015 gchar *devices_filename;
2016 GError *error = NULL;
2017 const gchar *elektroid_elektron_json;
2018
2019 parser = json_parser_new ();
2020
2021 elektroid_elektron_json = getenv ("ELEKTROID_ELEKTRON_JSON");
2022
2023 if (elektroid_elektron_json)
2024 {
2025 devices_filename = strdup (elektroid_elektron_json);
2026 }
2027 else
2028 {
2029 devices_filename = get_expanded_dir (CONF_DIR DEVICES_FILE);
2030 }
2031
2032 if (!json_parser_load_from_file (parser, devices_filename, &error))
2033 {
2034 debug_print (1, "%s\n", error->message);
2035 g_clear_error (&error);
2036
2037 g_free (devices_filename);
2038 devices_filename = strdup (DATADIR DEVICES_FILE);
2039
2040 debug_print (1, "Falling back to %s...\n", devices_filename);
2041
2042 if (!json_parser_load_from_file (parser, devices_filename, &error))
2043 {
2044 error_print ("%s", error->message);
2045 g_clear_error (&error);
2046 err = -ENODEV;
2047 goto cleanup_parser;
2048 }
2049 }
2050
2051 reader = json_reader_new (json_parser_get_root (parser));
2052 if (!reader)
2053 {
2054 error_print ("Unable to read from parser");
2055 err = -ENODEV;
2056 goto cleanup_parser;
2057 }
2058
2059 if (!json_reader_is_array (reader))
2060 {
2061 error_print ("Not an array\n");
2062 err = -ENODEV;
2063 goto cleanup_reader;
2064 }
2065
2066 devices = json_reader_count_elements (reader);
2067 if (!devices)
2068 {
2069 debug_print (1, "No devices found\n");
2070 err = -ENODEV;
2071 goto cleanup_reader;
2072 }
2073
2074 err = -ENODEV;
2075 for (int i = 0; i < devices; i++)
2076 {
2077 if (!json_reader_read_element (reader, i))
2078 {
2079 error_print ("Cannot read element %d. Continuing...\n", i);
2080 continue;
2081 }
2082
2083 if (!json_reader_read_member (reader, DEV_TAG_ID))
2084 {
2085 error_print ("Cannot read member '%s'. Continuing...\n",
2086 DEV_TAG_ID);
2087 continue;
2088 }
2089 device_desc->id = json_reader_get_int_value (reader);
2090 json_reader_end_member (reader);
2091
2092 if (device_desc->id != id)
2093 {
2094 json_reader_end_element (reader);
2095 continue;
2096 }
2097
2098 err = 0;
2099 debug_print (1, "Device %d found\n", id);
2100
2101 if (!json_reader_read_member (reader, DEV_TAG_NAME))
2102 {
2103 error_print ("Cannot read member '%s'. Stopping...\n",
2104 DEV_TAG_NAME);
2105 json_reader_end_element (reader);
2106 err = -ENODEV;
2107 break;
2108 }
2109 snprintf (device_desc->name, LABEL_MAX, "%s",
2110 json_reader_get_string_value (reader));
2111 json_reader_end_member (reader);
2112
2113 if (!json_reader_read_member (reader, DEV_TAG_ALIAS))
2114 {
2115 error_print ("Cannot read member '%s'. Stopping...\n",
2116 DEV_TAG_ALIAS);
2117 json_reader_end_element (reader);
2118 err = -ENODEV;
2119 break;
2120 }
2121 snprintf (device_desc->alias, LABEL_MAX, "%s",
2122 json_reader_get_string_value (reader));
2123 json_reader_end_member (reader);
2124
2125 if (!json_reader_read_member (reader, DEV_TAG_FILESYSTEMS))
2126 {
2127 error_print ("Cannot read member '%s'. Stopping...\n",
2128 DEV_TAG_FILESYSTEMS);
2129 json_reader_end_element (reader);
2130 err = -ENODEV;
2131 break;
2132 }
2133 device_desc->filesystems = json_reader_get_int_value (reader);
2134 json_reader_end_member (reader);
2135
2136 if (!json_reader_read_member (reader, DEV_TAG_STORAGE))
2137 {
2138 error_print ("Cannot read member '%s'. Stopping...\n",
2139 DEV_TAG_STORAGE);
2140 json_reader_end_element (reader);
2141 err = -ENODEV;
2142 break;
2143 }
2144 device_desc->storage = json_reader_get_int_value (reader);
2145 json_reader_end_member (reader);
2146
2147 break;
2148 }
2149
2150 cleanup_reader:
2151 g_object_unref (reader);
2152 cleanup_parser:
2153 g_object_unref (parser);
2154 g_free (devices_filename);
2155 if (err)
2156 {
2157 device_desc->id = -1;
2158 }
2159 return err;
2160 }
2161
2162 GByteArray *
2163 elektron_ping (struct backend *backend)
2164 {
2165 GByteArray *tx_msg, *rx_msg;
2166 struct elektron_data *data = g_malloc (sizeof (struct elektron_data));
2167
2168 data->seq = 0;
2169 backend->data = data;
2170
2171 tx_msg = elektron_new_msg (PING_REQUEST, sizeof (PING_REQUEST));
2172 rx_msg = elektron_tx_and_rx_timeout (backend, tx_msg,
2173 BE_SYSEX_TIMEOUT_GUESS_MS);
2174 if (!rx_msg)
2175 {
2176 backend->data = NULL;
2177 g_free (data);
2178 }
2179
2180
2181 return rx_msg;
2182 }
2183
2184 gint
2185 elektron_handshake (struct backend *backend)
2186 {
2187 guint8 id;
2188 gchar *overbridge_name;
2189 GByteArray *tx_msg, *rx_msg;
2190 struct elektron_data *data;
2191
2192 rx_msg = elektron_ping (backend);
2193 if (!rx_msg)
2194 {
2195 return -ENODEV;
2196 }
2197
2198 data = backend->data;
2199
2200 overbridge_name = strdup ((gchar *) & rx_msg->data[7 + rx_msg->data[6]]);
2201 id = rx_msg->data[5];
2202 free_msg (rx_msg);
2203
2204 if (elektron_load_device_desc (&backend->device_desc, id))
2205 {
2206 backend->data = NULL;
2207 g_free (overbridge_name);
2208 g_free (data);
2209 return -ENODEV;
2210 }
2211
2212 tx_msg = elektron_new_msg (SOFTWARE_VERSION_REQUEST,
2213 sizeof (SOFTWARE_VERSION_REQUEST));
2214 rx_msg = elektron_tx_and_rx (backend, tx_msg);
2215 if (!rx_msg)
2216 {
2217 backend->data = NULL;
2218 g_free (overbridge_name);
2219 g_free (data);
2220 return -ENODEV;
2221 }
2222 if (snprintf (data->fw_version, LABEL_MAX, "%s",
2223 (gchar *) & rx_msg->data[10]) >= LABEL_MAX)
2224 {
2225 error_print ("Firmware version truncated\n");
2226 }
2227 free_msg (rx_msg);
2228
2229 if (debug_level > 1)
2230 {
2231 tx_msg = elektron_new_msg (DEVICEUID_REQUEST,
2232 sizeof (DEVICEUID_REQUEST));
2233 rx_msg = elektron_tx_and_rx (backend, tx_msg);
2234 if (rx_msg)
2235 {
2236 debug_print (1, "UID: %x\n", *((guint32 *) & rx_msg->data[5]));
2237 free_msg (rx_msg);
2238 }
2239 }
2240
2241 if (snprintf (backend->device_name, LABEL_MAX, "%s %s (%s)",
2242 backend->device_desc.name, data->fw_version,
2243 overbridge_name) >= LABEL_MAX)
2244 {
2245 error_print ("Device name truncated\n");
2246 }
2247 debug_print (1, "Connected to %s\n", backend->device_name);
2248
2249 g_free (overbridge_name);
2250
2251 backend->fs_ops = FS_OPERATIONS;
2252 backend->destroy_data = backend_destroy_data;
2253 backend->upgrade_os = elektron_upgrade_os;
2254 backend->get_storage_stats = elektron_get_storage_stats;
2255
2256 return 0;
2257 }
2258
2259 static guint
2260 elektron_next_data_entry (struct item_iterator *iter)
2261 {
2262 gchar *name_cp1252;
2263 guint32 *data32;
2264 guint16 *data16;
2265 guint8 type;
2266 guint8 has_children;
2267 struct elektron_iterator_data *data = iter->data;
2268
2269 if (data->pos == data->msg->len)
2270 {
2271 return -ENOENT;
2272 }
2273
2274 name_cp1252 = (gchar *) & data->msg->data[data->pos];
2275 elektron_get_utf8 (iter->item.name, name_cp1252);
2276 data->pos += strlen (name_cp1252) + 1;
2277 has_children = data->msg->data[data->pos];
2278 data->pos++;
2279 type = data->msg->data[data->pos];
2280 data->pos++;
2281
2282 switch (type)
2283 {
2284 case 1:
2285 iter->item.type = ELEKTROID_DIR;
2286 data->pos += sizeof (guint32); // child entries
2287 iter->item.size = 0;
2288 iter->item.id = -1;
2289 data->operations = 0;
2290 data->has_valid_data = 0;
2291 data->has_metadata = 0;
2292 break;
2293 case 2:
2294 iter->item.type = has_children ? ELEKTROID_DIR : ELEKTROID_FILE;
2295
2296 data32 = (guint32 *) & data->msg->data[data->pos];
2297 iter->item.id = be32toh (*data32); //index
2298 data->pos += sizeof (gint32);
2299
2300 data32 = (guint32 *) & data->msg->data[data->pos];
2301 iter->item.size = be32toh (*data32);
2302 data->pos += sizeof (guint32);
2303
2304 data16 = (guint16 *) & data->msg->data[data->pos];
2305 data->operations = be16toh (*data16);
2306 data->pos += sizeof (guint16);
2307
2308 data->has_valid_data = data->msg->data[data->pos];
2309 data->pos++;
2310
2311 data->has_metadata = data->msg->data[data->pos];
2312 data->pos++;
2313
2314 break;
2315 default:
2316 error_print ("Unrecognized data entry: %d\n", iter->item.type);
2317 break;
2318 }
2319
2320 return 0;
2321 }
2322
2323 static gchar *
2324 elektron_add_prefix_to_path (const gchar * dir, const gchar * prefix)
2325 {
2326 gchar *full = malloc (PATH_MAX);
2327
2328 if (prefix)
2329 {
2330 snprintf (full, PATH_MAX, "%s%s", prefix, dir);
2331 }
2332 else
2333 {
2334 strcpy (full, dir);
2335 }
2336
2337 return full;
2338 }
2339
2340 static gint
2341 elektron_read_data_dir_prefix (struct backend *backend,
2342 struct item_iterator *iter,
2343 const gchar * dir, const char *prefix)
2344 {
2345 int res;
2346 GByteArray *tx_msg;
2347 GByteArray *rx_msg;
2348 gchar *dir_w_prefix = elektron_add_prefix_to_path (dir, prefix);
2349
2350 tx_msg = elektron_new_msg_list (dir_w_prefix, 0, 0, 1);
2351 g_free (dir_w_prefix);
2352 if (!tx_msg)
2353 {
2354 return -EINVAL;
2355 }
2356
2357 rx_msg = elektron_tx_and_rx (backend, tx_msg);
2358 if (!rx_msg)
2359 {
2360 return -EIO;
2361 }
2362
2363 res = elektron_get_msg_status (rx_msg);
2364 if (!res)
2365 {
2366 free_msg (rx_msg);
2367 return -ENOTDIR;
2368 }
2369
2370 return elektron_init_iterator (iter, rx_msg, elektron_next_data_entry,
2371 FS_DATA_ALL, FALSE);
2372 }
2373
2374 static gint
2375 elektron_read_data_dir_any (struct backend *backend,
2376 struct item_iterator *iter, const gchar * dir)
2377 {
2378 return elektron_read_data_dir_prefix (backend, iter, dir, NULL);
2379 }
2380
2381 static gint
2382 elektron_read_data_dir_prj (struct backend *backend,
2383 struct item_iterator *iter, const gchar * dir)
2384 {
2385 return elektron_read_data_dir_prefix (backend, iter, dir,
2386 FS_DATA_PRJ_PREFIX);
2387 }
2388
2389 static gint
2390 elektron_read_data_dir_snd (struct backend *backend,
2391 struct item_iterator *iter, const gchar * dir)
2392 {
2393 return elektron_read_data_dir_prefix (backend, iter, dir,
2394 FS_DATA_SND_PREFIX);
2395 }
2396
2397 static gint
2398 elektron_dst_src_data_prefix_common (struct backend *backend,
2399 const gchar * src, const gchar * dst,
2400 const char *prefix,
2401 const guint8 * op_data, guint len)
2402 {
2403 gint res;
2404 char *src_w_prefix = elektron_add_prefix_to_path (src, prefix);
2405 char *dst_w_prefix = elektron_add_prefix_to_path (dst, prefix);
2406
2407 res = elektron_src_dst_common (backend, src_w_prefix, dst_w_prefix,
2408 op_data, len);
2409 g_free (src_w_prefix);
2410 g_free (dst_w_prefix);
2411
2412 return res;
2413 }
2414
2415 static gint
2416 elektron_move_data_item_prefix (struct backend *backend, const gchar * src,
2417 const gchar * dst, const char *prefix)
2418 {
2419 return elektron_dst_src_data_prefix_common (backend, src, dst, prefix,
2420 DATA_MOVE_REQUEST,
2421 sizeof (DATA_MOVE_REQUEST));
2422 }
2423
2424 static gint
2425 elektron_move_data_item_any (struct backend *backend, const gchar * src,
2426 const gchar * dst)
2427 {
2428 return elektron_move_data_item_prefix (backend, src, dst, NULL);
2429 }
2430
2431 static gint
2432 elektron_move_data_item_prj (struct backend *backend, const gchar * src,
2433 const gchar * dst)
2434 {
2435 return elektron_move_data_item_prefix (backend, src, dst,
2436 FS_DATA_PRJ_PREFIX);
2437 }
2438
2439 static gint
2440 elektron_move_data_item_snd (struct backend *backend, const gchar * src,
2441 const gchar * dst)
2442 {
2443 return elektron_move_data_item_prefix (backend, src, dst,
2444 FS_DATA_SND_PREFIX);
2445 }
2446
2447 static gint
2448 elektron_copy_data_item_prefix (struct backend *backend, const gchar * src,
2449 const gchar * dst, const gchar * prefix)
2450 {
2451 return elektron_dst_src_data_prefix_common (backend, src, dst, prefix,
2452 DATA_COPY_REQUEST,
2453 sizeof (DATA_COPY_REQUEST));
2454 }
2455
2456 static gint
2457 elektron_copy_data_item_any (struct backend *backend, const gchar * src,
2458 const gchar * dst)
2459 {
2460 return elektron_copy_data_item_prefix (backend, src, dst, NULL);
2461 }
2462
2463 static gint
2464 elektron_copy_data_item_prj (struct backend *backend, const gchar * src,
2465 const gchar * dst)
2466 {
2467 return elektron_copy_data_item_prefix (backend, src, dst,
2468 FS_DATA_PRJ_PREFIX);
2469 }
2470
2471 static gint
2472 elektron_copy_data_item_snd (struct backend *backend, const gchar * src,
2473 const gchar * dst)
2474 {
2475 return elektron_copy_data_item_prefix (backend, src, dst,
2476 FS_DATA_SND_PREFIX);
2477 }
2478
2479 static gint
2480 elektron_path_data_prefix_common (struct backend *backend,
2481 const gchar * path, const char *prefix,
2482 const guint8 * op_data, guint len)
2483 {
2484 gint res;
2485 char *path_w_prefix = elektron_add_prefix_to_path (path, prefix);
2486
2487 res = elektron_path_common (backend, path_w_prefix, op_data, len);
2488 g_free (path_w_prefix);
2489
2490 return res;
2491 }
2492
2493 static gint
2494 elektron_clear_data_item_prefix (struct backend *backend,
2495 const gchar * path, const gchar * prefix)
2496 {
2497 return elektron_path_data_prefix_common (backend, path, prefix,
2498 DATA_CLEAR_REQUEST,
2499 sizeof (DATA_CLEAR_REQUEST));
2500 }
2501
2502 static gint
2503 elektron_clear_data_item_any (struct backend *backend, const gchar * path)
2504 {
2505 return elektron_clear_data_item_prefix (backend, path, NULL);
2506 }
2507
2508 static gint
2509 elektron_clear_data_item_prj (struct backend *backend, const gchar * path)
2510 {
2511 return elektron_clear_data_item_prefix (backend, path, FS_DATA_PRJ_PREFIX);
2512 }
2513
2514 static gint
2515 elektron_clear_data_item_snd (struct backend *backend, const gchar * path)
2516 {
2517 return elektron_clear_data_item_prefix (backend, path, FS_DATA_SND_PREFIX);
2518 }
2519
2520 static gint
2521 elektron_swap_data_item_prefix (struct backend *backend, const gchar * src,
2522 const gchar * dst, const gchar * prefix)
2523 {
2524 return elektron_dst_src_data_prefix_common (backend, src, dst, prefix,
2525 DATA_SWAP_REQUEST,
2526 sizeof (DATA_SWAP_REQUEST));
2527 }
2528
2529 static gint
2530 elektron_swap_data_item_any (struct backend *backend, const gchar * src,
2531 const gchar * dst)
2532 {
2533 return elektron_swap_data_item_prefix (backend, src, dst, NULL);
2534 }
2535
2536 static gint
2537 elektron_swap_data_item_prj (struct backend *backend, const gchar * src,
2538 const gchar * dst)
2539 {
2540 return elektron_swap_data_item_prefix (backend, src, dst,
2541 FS_DATA_PRJ_PREFIX);
2542 }
2543
2544 static gint
2545 elektron_swap_data_item_snd (struct backend *backend, const gchar * src,
2546 const gchar * dst)
2547 {
2548 return elektron_swap_data_item_prefix (backend, src, dst,
2549 FS_DATA_SND_PREFIX);
2550 }
2551
2552 static gint
2553 elektron_open_datum (struct backend *backend, const gchar * path,
2554 guint32 * jid, gint mode, guint32 size)
2555 {
2556 guint32 *data32;
2557 guint32 sizebe;
2558 guint32 chunk_size;
2559 guint8 compression;
2560 GByteArray *rx_msg;
2561 GByteArray *tx_msg;
2562 const guint8 *data;
2563 guint len;
2564 gchar *path_cp1252;
2565 gint res = 0;
2566
2567 if (mode == O_RDONLY)
2568 {
2569 data = DATA_READ_OPEN_REQUEST;
2570 len = sizeof (DATA_READ_OPEN_REQUEST);
2571 }
2572 else if (mode == O_WRONLY)
2573 {
2574 data = DATA_WRITE_OPEN_REQUEST;
2575 len = sizeof (DATA_WRITE_OPEN_REQUEST);
2576 }
2577 else
2578 {
2579 return -EINVAL;
2580 }
2581
2582 tx_msg = elektron_new_msg (data, len);
2583 if (!tx_msg)
2584 {
2585 return -ENOMEM;
2586 }
2587
2588 path_cp1252 = elektron_get_cp1252 (path);
2589
2590 if (mode == O_RDONLY)
2591 {
2592 g_byte_array_append (tx_msg, (guint8 *) path_cp1252,
2593 strlen (path_cp1252) + 1);
2594 chunk_size = htobe32 (DATA_TRANSF_BLOCK_BYTES);
2595 g_byte_array_append (tx_msg, (guint8 *) & chunk_size, sizeof (guint32));
2596 compression = 1;
2597 g_byte_array_append (tx_msg, &compression, sizeof (guint8));
2598 }
2599
2600 if (mode == O_WRONLY)
2601 {
2602 sizebe = htobe32 (size);
2603 g_byte_array_append (tx_msg, (guint8 *) & sizebe, sizeof (guint32));
2604 g_byte_array_append (tx_msg, (guint8 *) path_cp1252,
2605 strlen (path_cp1252) + 1);
2606 }
2607
2608 rx_msg = elektron_tx_and_rx (backend, tx_msg);
2609 if (!rx_msg)
2610 {
2611 res = -EIO;
2612 goto cleanup;
2613 }
2614
2615 if (!elektron_get_msg_status (rx_msg))
2616 {
2617 res = -EPERM;
2618 error_print ("%s (%s)\n", snd_strerror (res),
2619 elektron_get_msg_string (rx_msg));
2620 free_msg (rx_msg);
2621 goto cleanup;
2622 }
2623
2624 data32 = (guint32 *) & rx_msg->data[6];
2625 *jid = be32toh (*data32);
2626
2627 if (mode == O_RDONLY)
2628 {
2629 data32 = (guint32 *) & rx_msg->data[10];
2630 chunk_size = be32toh (*data32);
2631
2632 compression = rx_msg->data[14];
2633
2634 debug_print (1,
2635 "Open datum info: job id: %d; chunk size: %d; compression: %d\n",
2636 *jid, chunk_size, compression);
2637 }
2638
2639 if (mode == O_WRONLY)
2640 {
2641 debug_print (1, "Open datum info: job id: %d\n", *jid);
2642 }
2643
2644 free_msg (rx_msg);
2645
2646 cleanup:
2647 g_free (path_cp1252);
2648 return res;
2649 }
2650
2651 static gint
2652 elektron_close_datum (struct backend *backend,
2653 guint32 jid, gint mode, guint32 wsize)
2654 {
2655 guint32 jidbe;
2656 guint32 wsizebe;
2657 guint32 r_jid;
2658 guint32 asize;
2659 guint32 *data32;
2660 GByteArray *rx_msg;
2661 GByteArray *tx_msg;
2662 const guint8 *data;
2663 guint len;
2664
2665 if (mode == O_RDONLY)
2666 {
2667 data = DATA_READ_CLOSE_REQUEST;
2668 len = sizeof (DATA_READ_CLOSE_REQUEST);
2669 }
2670 else if (mode == O_WRONLY)
2671 {
2672 data = DATA_WRITE_CLOSE_REQUEST;
2673 len = sizeof (DATA_WRITE_CLOSE_REQUEST);
2674 }
2675 else
2676 {
2677 return -EINVAL;
2678 }
2679
2680 tx_msg = elektron_new_msg (data, len);
2681 if (!tx_msg)
2682 {
2683 return -ENOMEM;
2684 }
2685
2686 jidbe = htobe32 (jid);
2687 g_byte_array_append (tx_msg, (guchar *) & jidbe, sizeof (guint32));
2688
2689 if (mode == O_WRONLY)
2690 {
2691 wsizebe = htobe32 (wsize);
2692 g_byte_array_append (tx_msg, (guchar *) & wsizebe, sizeof (guint32));
2693 }
2694
2695 rx_msg = elektron_tx_and_rx (backend, tx_msg);
2696 if (!rx_msg)
2697 {
2698 return -EIO;
2699 }
2700
2701 if (!elektron_get_msg_status (rx_msg))
2702 {
2703 error_print ("%s (%s)\n", snd_strerror (-EPERM),
2704 elektron_get_msg_string (rx_msg));
2705 free_msg (rx_msg);
2706 return -EPERM;
2707 }
2708
2709 data32 = (guint32 *) & rx_msg->data[6];
2710 r_jid = be32toh (*data32);
2711
2712 data32 = (guint32 *) & rx_msg->data[10];
2713 asize = be32toh (*data32);
2714
2715 debug_print (1, "Close datum info: job id: %d; size: %d\n", r_jid, asize);
2716
2717 free_msg (rx_msg);
2718
2719 if (mode == O_WRONLY && asize != wsize)
2720 {
2721 error_print
2722 ("Actual download bytes (%d) differs from expected ones (%d)\n",
2723 asize, wsize);
2724 return -EINVAL;
2725 }
2726
2727 return 0;
2728 }
2729
2730 static gint
2731 elektron_download_data_prefix (struct backend *backend, const gchar * path,
2732 GByteArray * output,
2733 struct job_control *control,
2734 const gchar * prefix)
2735 {
2736 gint res;
2737 guint32 seq;
2738 guint32 seqbe;
2739 guint32 jid;
2740 guint32 r_jid;
2741 guint32 r_seq;
2742 guint32 status;
2743 guint8 last;
2744 guint32 hash;
2745 guint32 *data32;
2746 guint32 jidbe;
2747 guint32 data_size;
2748 gboolean active;
2749 GByteArray *rx_msg;
2750 GByteArray *tx_msg;
2751 gchar *path_w_prefix = elektron_add_prefix_to_path (path, prefix);
2752
2753 res = elektron_open_datum (backend, path_w_prefix, &jid, O_RDONLY, 0);
2754 g_free (path_w_prefix);
2755 if (res)
2756 {
2757 return -EIO;
2758 }
2759
2760 usleep (BE_REST_TIME_US);
2761
2762 jidbe = htobe32 (jid);
2763
2764 res = 0;
2765 seq = 0;
2766 last = 0;
2767 control->data = NULL;
2768 g_mutex_lock (&control->mutex);
2769 active = control->active;
2770 g_mutex_unlock (&control->mutex);
2771 while (!last && active)
2772 {
2773 tx_msg =
2774 elektron_new_msg (DATA_READ_PARTIAL_REQUEST,
2775 sizeof (DATA_READ_PARTIAL_REQUEST));
2776 g_byte_array_append (tx_msg, (guint8 *) & jidbe, sizeof (guint32));
2777 seqbe = htobe32 (seq);
2778 g_byte_array_append (tx_msg, (guint8 *) & seqbe, sizeof (guint32));
2779 rx_msg = elektron_tx_and_rx (backend, tx_msg);
2780 if (!rx_msg)
2781 {
2782 res = -EIO;
2783 break;
2784 }
2785
2786 if (!elektron_get_msg_status (rx_msg))
2787 {
2788 res = -EPERM;
2789 error_print ("%s (%s)\n", snd_strerror (res),
2790 elektron_get_msg_string (rx_msg));
2791 free_msg (rx_msg);
2792 break;
2793 }
2794
2795 data32 = (guint32 *) & rx_msg->data[6];
2796 r_jid = be32toh (*data32);
2797
2798 data32 = (guint32 *) & rx_msg->data[10];
2799 r_seq = be32toh (*data32);
2800
2801 data32 = (guint32 *) & rx_msg->data[14];
2802 status = be32toh (*data32);
2803
2804 last = rx_msg->data[18];
2805
2806 data32 = (guint32 *) & rx_msg->data[19];
2807 hash = be32toh (*data32);
2808
2809 data32 = (guint32 *) & rx_msg->data[23];
2810 data_size = be32toh (*data32);
2811
2812 if (data_size)
2813 {
2814 debug_print (1,
2815 "Read datum info: job id: %d; last: %d; seq: %d; status: %d; hash: 0x%08x\n",
2816 r_jid, last, r_seq, status, hash);
2817
2818 g_byte_array_append (output, (guint8 *) & rx_msg->data[27],
2819 data_size);
2820 }
2821 else
2822 {
2823 // Sometimes, the first message returns 0 data size and the rest of the parameters are not initialized.
2824 debug_print (1,
2825 "Read datum info: job id: %d; last: %d, hash: 0x%08x\n",
2826 r_jid, last, hash);
2827 status = 0;
2828 }
2829
2830 free_msg (rx_msg);
2831 seq++;
2832
2833 if (control)
2834 {
2835 set_job_control_progress (control, status / 1000.0);
2836 g_mutex_lock (&control->mutex);
2837 active = control->active;
2838 g_mutex_unlock (&control->mutex);
2839 }
2840
2841 usleep (BE_REST_TIME_US);
2842 }
2843
2844 return elektron_close_datum (backend, jid, O_RDONLY, 0);
2845 }
2846
2847 static gint
2848 elektron_download_data_any (struct backend *backend, const gchar * path,
2849 GByteArray * output, struct job_control *control)
2850 {
2851 control->parts = 1;
2852 control->part = 0;
2853 return elektron_download_data_prefix (backend, path, output, control, NULL);
2854 }
2855
2856 static gint
2857 elektron_download_data_prj (struct backend *backend, const gchar * path,
2858 GByteArray * output, struct job_control *control)
2859 {
2860 return elektron_download_data_prefix (backend, path, output, control,
2861 FS_DATA_PRJ_PREFIX);
2862 }
2863
2864 static gint
2865 elektron_download_data_snd (struct backend *backend, const gchar * path,
2866 GByteArray * output, struct job_control *control)
2867 {
2868 return elektron_download_data_prefix (backend, path, output, control,
2869 FS_DATA_SND_PREFIX);
2870 }
2871
2872 static gchar *
2873 elektron_get_download_name (struct backend *backend,
2874 struct item_iterator *remote_iter,
2875 const struct fs_operations *ops,
2876 const gchar * src_path)
2877 {
2878 gint32 id;
2879 const gchar *src_dir;
2880 gchar *namec, *name, *src_dirc;
2881 gint ret;
2882 gboolean new = FALSE;
2883
2884 namec = strdup (src_path);
2885 name = basename (namec);
2886
2887 if (ops->fs == FS_SAMPLES || ops->fs == FS_RAW_ALL
2888 || ops->fs == FS_RAW_PRESETS)
2889 {
2890 name = strdup (name);
2891 goto end;
2892 }
2893
2894 if (!remote_iter)
2895 {
2896 new = TRUE;
2897 remote_iter = malloc (sizeof (struct item_iterator));
2898 src_dirc = strdup (src_path);
2899 src_dir = dirname (src_dirc);
2900 ret = ops->readdir (backend, remote_iter, src_dir);
2901 g_free (src_dirc);
2902 if (ret)
2903 {
2904 name = NULL;
2905 goto cleanup;
2906 }
2907 }
2908
2909 id = atoi (name);
2910 name = NULL;
2911
2912 while (!next_item_iterator (remote_iter))
2913 {
2914 if (remote_iter->item.id == id)
2915 {
2916 name = g_strdup (remote_iter->item.name);
2917 break;
2918 }
2919 }
2920
2921 cleanup:
2922 if (new)
2923 {
2924 free_item_iterator (remote_iter);
2925 }
2926 g_free (namec);
2927 end:
2928 return name;
2929 }
2930
2931 static gint
2932 elektron_download_pkg (struct backend *backend, const gchar * path,
2933 GByteArray * output, struct job_control *control,
2934 enum package_type type,
2935 const struct fs_operations *ops,
2936 fs_remote_file_op download)
2937 {
2938 gint ret;
2939 gchar *pkg_name;
2940 struct package pkg;
2941 struct elektron_data *data = backend->data;
2942
2943 pkg_name = elektron_get_download_name (backend, NULL, ops, path);
2944 if (!pkg_name)
2945 {
2946 return -1;
2947 }
2948
2949 if (package_begin
2950 (&pkg, pkg_name, data->fw_version, &backend->device_desc, type))
2951 {
2952 g_free (pkg_name);
2953 return -1;
2954 }
2955
2956 ret =
2957 package_receive_pkg_resources (&pkg, path, control, backend, download,
2958 elektron_download_sample_part);
2959 ret = ret || package_end (&pkg, output);
2960
2961 package_destroy (&pkg);
2962 return ret;
2963 }
2964
2965 static gint
2966 elektron_download_data_snd_pkg (struct backend *backend,
2967 const gchar * path, GByteArray * output,
2968 struct job_control *control)
2969 {
2970 return elektron_download_pkg (backend, path, output, control,
2971 PKG_FILE_TYPE_SOUND,
2972 &FS_DATA_SND_OPERATIONS,
2973 elektron_download_data_snd);
2974 }
2975
2976 static gint
2977 elektron_download_data_prj_pkg (struct backend *backend,
2978 const gchar * path, GByteArray * output,
2979 struct job_control *control)
2980 {
2981 return elektron_download_pkg (backend, path, output, control,
2982 PKG_FILE_TYPE_PROJECT,
2983 &FS_DATA_PRJ_OPERATIONS,
2984 elektron_download_data_prj);
2985 }
2986
2987 static gint
2988 elektron_download_raw_pst_pkg (struct backend *backend, const gchar * path,
2989 GByteArray * output,
2990 struct job_control *control)
2991 {
2992 return elektron_download_pkg (backend, path, output, control,
2993 PKG_FILE_TYPE_PRESET,
2994 &FS_RAW_ANY_OPERATIONS,
2995 elektron_download_raw);
2996 }
2997
2998 static gchar *
2999 elektron_get_upload_path_smplrw (struct backend *backend,
3000 struct item_iterator *remote_iter,
3001 const struct fs_operations *ops,
3002 const gchar * dst_dir,
3003 const gchar * src_path, gint32 * next_index)
3004 {
3005 gchar *path, *namec, *name, *aux;
3006
3007 namec = strdup (src_path);
3008 name = basename (namec);
3009 remove_ext (name);
3010 aux = chain_path (dst_dir, name);
3011 g_free (namec);
3012
3013 if (ops->fs == FS_RAW_ALL || ops->fs == FS_RAW_PRESETS)
3014 {
3015 path = elektron_add_ext_to_mc_snd (aux);
3016 g_free (aux);
3017 }
3018 else
3019 {
3020 path = aux;
3021 }
3022 return path;
3023 }
3024
3025 static gchar *
3026 elektron_get_upload_path_data (struct backend *backend,
3027 struct item_iterator *remote_iter,
3028 const struct fs_operations *ops,
3029 const gchar * dst_dir,
3030 const gchar * src_path, gint32 * next_index)
3031 {
3032 gchar *indexs, *path;
3033 gboolean new = FALSE;
3034
3035 if (!remote_iter)
3036 {
3037 new = TRUE;
3038 remote_iter = malloc (sizeof (struct item_iterator));
3039 if (ops->readdir (backend, remote_iter, dst_dir))
3040 {
3041 return strdup (dst_dir);
3042 }
3043 }
3044
3045 if (remote_iter->item.id == *next_index)
3046 {
3047 (*next_index)++;
3048 }
3049 else
3050 {
3051 while (!next_item_iterator (remote_iter))
3052 {
3053 if (remote_iter->item.id > *next_index)
3054 {
3055 break;
3056 }
3057 (*next_index)++;
3058 }
3059 }
3060
3061 if (new)
3062 {
3063 free_item_iterator (remote_iter);
3064 }
3065
3066 indexs = malloc (PATH_MAX);
3067 snprintf (indexs, PATH_MAX, "%d", *next_index);
3068 path = chain_path (dst_dir, indexs);
3069 g_free (indexs);
3070
3071 (*next_index)++;
3072
3073 return path;
3074 }
3075
3076 static gchar *
3077 elektron_get_download_path (struct backend *backend,
3078 struct item_iterator *remote_iter,
3079 const struct fs_operations *ops,
3080 const gchar * dst_dir, const gchar * src_path)
3081 {
3082 gchar *path, *src_pathc, *name, *dl_ext, *filename;
3083 const gchar *src_fpath, *md_ext, *ext = get_ext (src_path);
3084
3085 // Examples:
3086 // 0:/soundbanks/A/1/.metadata
3087 // 0:/loops/sample
3088
3089 src_pathc = strdup (src_path);
3090 if (ext && strcmp (ext, "metadata") == 0)
3091 {
3092 src_fpath = dirname (src_pathc);
3093 md_ext = ".metadata";
3094 }
3095 else
3096 {
3097 src_fpath = src_pathc;
3098 md_ext = "";
3099 }
3100
3101 name = elektron_get_download_name (backend, remote_iter, ops, src_fpath);
3102 if (name)
3103 {
3104 dl_ext = ops->get_ext (&backend->device_desc, ops);
3105 filename = malloc (PATH_MAX);
3106 snprintf (filename, PATH_MAX, "%s.%s%s", name, dl_ext, md_ext);
3107 path = chain_path (dst_dir, filename);
3108 g_free (name);
3109 g_free (dl_ext);
3110 g_free (filename);
3111 }
3112 else
3113 {
3114 path = NULL;
3115 }
3116
3117 g_free (src_pathc);
3118 return path;
3119 }
3120
3121 static gint
3122 elektron_upload_data_prefix (struct backend *backend, const gchar * path,
3123 GByteArray * array,
3124 struct job_control *control,
3125 const gchar * prefix)
3126 {
3127 gint res;
3128 guint32 seq;
3129 guint32 jid;
3130 guint32 crc;
3131 guint32 len;
3132 guint32 r_jid;
3133 guint32 r_seq;
3134 guint32 offset;
3135 guint32 *data32;
3136 guint32 jidbe;
3137 guint32 aux32;
3138 gboolean active;
3139 guint32 total;
3140 GByteArray *rx_msg;
3141 GByteArray *tx_msg;
3142 gchar *path_w_prefix = elektron_add_prefix_to_path (path, prefix);
3143
3144 res =
3145 elektron_open_datum (backend, path_w_prefix, &jid, O_WRONLY, array->len);
3146 g_free (path_w_prefix);
3147 if (res)
3148 {
3149 goto end;
3150 }
3151
3152 usleep (BE_REST_TIME_US);
3153
3154 jidbe = htobe32 (jid);
3155
3156 seq = 0;
3157 offset = 0;
3158 control->data = NULL;
3159 if (control)
3160 {
3161 g_mutex_lock (&control->mutex);
3162 active = control->active;
3163 g_mutex_unlock (&control->mutex);
3164 }
3165 else
3166 {
3167 active = TRUE;
3168 }
3169
3170 while (offset < array->len && active)
3171 {
3172 tx_msg =
3173 elektron_new_msg (DATA_WRITE_PARTIAL_REQUEST,
3174 sizeof (DATA_WRITE_PARTIAL_REQUEST));
3175 g_byte_array_append (tx_msg, (guint8 *) & jidbe, sizeof (guint32));
3176 aux32 = htobe32 (seq);
3177 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3178
3179 if (offset + DATA_TRANSF_BLOCK_BYTES < array->len)
3180 {
3181 len = DATA_TRANSF_BLOCK_BYTES;
3182 }
3183 else
3184 {
3185 len = array->len - offset;
3186 }
3187
3188 crc = crc32 (0xffffffff, &array->data[offset], len);
3189 aux32 = htobe32 (crc);
3190 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3191
3192 aux32 = htobe32 (len);
3193 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3194
3195 g_byte_array_append (tx_msg, &array->data[offset], len);
3196
3197 rx_msg = elektron_tx_and_rx (backend, tx_msg);
3198 if (!rx_msg)
3199 {
3200 res = -EIO;
3201 goto end;
3202 }
3203
3204 usleep (BE_REST_TIME_US);
3205
3206 if (!elektron_get_msg_status (rx_msg))
3207 {
3208 res = -EPERM;
3209 error_print ("%s (%s)\n", snd_strerror (res),
3210 elektron_get_msg_string (rx_msg));
3211 free_msg (rx_msg);
3212 break;
3213 }
3214
3215 data32 = (guint32 *) & rx_msg->data[6];
3216 r_jid = be32toh (*data32);
3217
3218 data32 = (guint32 *) & rx_msg->data[10];
3219 r_seq = be32toh (*data32);
3220
3221 data32 = (guint32 *) & rx_msg->data[14];
3222 total = be32toh (*data32);
3223
3224 free_msg (rx_msg);
3225
3226 debug_print (1,
3227 "Write datum info: job id: %d; seq: %d; total: %d\n",
3228 r_jid, r_seq, total);
3229
3230 seq++;
3231 offset += len;
3232
3233 if (total != offset)
3234 {
3235 error_print
3236 ("Actual upload bytes (%d) differs from expected ones (%d)\n",
3237 total, offset);
3238 }
3239
3240 set_job_control_progress (control, offset / (gdouble) array->len);
3241 g_mutex_lock (&control->mutex);
3242 active = control->active;
3243 g_mutex_unlock (&control->mutex);
3244 }
3245
3246 debug_print (2, "%d bytes sent\n", offset);
3247
3248 res = elektron_close_datum (backend, jid, O_WRONLY, array->len);
3249
3250 end:
3251 return res;
3252 }
3253
3254 static gint
3255 elektron_upload_data_any (struct backend *backend, const gchar * path,
3256 GByteArray * array, struct job_control *control)
3257 {
3258 control->parts = 1;
3259 control->part = 0;
3260 return elektron_upload_data_prefix (backend, path, array, control, NULL);
3261 }
3262
3263 static gint
3264 elektron_upload_data_prj (struct backend *backend, const gchar * path,
3265 GByteArray * array, struct job_control *control)
3266 {
3267 return elektron_upload_data_prefix (backend, path, array, control,
3268 FS_DATA_PRJ_PREFIX);
3269 }
3270
3271 static gint
3272 elektron_upload_data_snd (struct backend *backend, const gchar * path,
3273 GByteArray * array, struct job_control *control)
3274 {
3275 return elektron_upload_data_prefix (backend, path, array, control,
3276 FS_DATA_SND_PREFIX);
3277 }
3278
3279 static gint
3280 elektron_upload_pkg (struct backend *backend, const gchar * path,
3281 GByteArray * input, struct job_control *control,
3282 guint8 type, const struct fs_operations *ops,
3283 fs_remote_file_op upload)
3284 {
3285 gint ret;
3286 struct package pkg;
3287
3288 ret = package_open (&pkg, input, &backend->device_desc);
3289 if (!ret)
3290 {
3291 ret = package_send_pkg_resources (&pkg, path, control, backend,
3292 upload, elektron_upload_sample_part);
3293 package_close (&pkg);
3294 }
3295 return ret;
3296 }
3297
3298 static gint
3299 elektron_upload_data_snd_pkg (struct backend *backend, const gchar * path,
3300 GByteArray * input, struct job_control *control)
3301 {
3302 return elektron_upload_pkg (backend, path, input, control,
3303 PKG_FILE_TYPE_SOUND,
3304 &FS_DATA_SND_OPERATIONS,
3305 elektron_upload_data_snd);
3306 }
3307
3308 static gint
3309 elektron_upload_data_prj_pkg (struct backend *backend, const gchar * path,
3310 GByteArray * input, struct job_control *control)
3311 {
3312 return elektron_upload_pkg (backend, path, input, control,
3313 PKG_FILE_TYPE_PROJECT,
3314 &FS_DATA_PRJ_OPERATIONS,
3315 elektron_upload_data_prj);
3316 }
3317
3318 static gint
3319 elektron_upload_raw_pst_pkg (struct backend *backend, const gchar * path,
3320 GByteArray * input, struct job_control *control)
3321 {
3322 return elektron_upload_pkg (backend, path, input, control,
3323 PKG_FILE_TYPE_PRESET,
3324 &FS_RAW_ANY_OPERATIONS, elektron_upload_raw);
3325 }
3326
3327 static gchar *
3328 elektron_get_dev_and_fs_ext (const struct device_desc *desc,
3329 const struct fs_operations *ops)
3330 {
3331 gchar *ext = malloc (LABEL_MAX);
3332 snprintf (ext, LABEL_MAX, "%s%s", desc->alias, ops->type_ext);
3333 return ext;
3334 }
3335
3336 gint
3337 elektron_sample_load (const gchar * path, GByteArray * sample,
3338 struct job_control *control)
3339 {
3340 guint frames;
3341 return sample_load_from_file (path, sample, control,
3342 &ELEKTRON_SAMPLE_PARAMS, &frames);
3343 }
3344
3345 gchar *
3346 elektron_get_sample_path_from_hash_size (struct backend *backend,
3347 guint32 hash, guint32 size)
3348 {
3349 guint32 aux32;
3350 gchar *path;
3351 GByteArray *rx_msg, *tx_msg =
3352 elektron_new_msg (FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST,
3353 sizeof
3354 (FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST));
3355
3356 aux32 = htobe32 (hash);
3357 memcpy (&tx_msg->data[5], &aux32, sizeof (guint32));
3358 aux32 = htobe32 (size);
3359 memcpy (&tx_msg->data[9], &aux32, sizeof (guint32));
3360
3361 rx_msg = elektron_tx_and_rx (backend, tx_msg);
3362 if (!rx_msg)
3363 {
3364 return NULL;
3365 }
3366
3367 if (elektron_get_msg_status (rx_msg))
3368 {
3369 path = strdup ((gchar *) & rx_msg->data[14]);
3370 }
3371 else
3372 {
3373 path = NULL;
3374 }
3375 g_byte_array_free (rx_msg, TRUE);
3376 return path;
3377 }
0 /*
1 * elektron.h
2 * Copyright (C) 2019 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef ELEKTRON_H
21 #define ELEKTRON_H
22
23 #include "utils.h"
24 #include "backend.h"
25
26 enum elektron_fs
27 {
28 FS_SAMPLES = 0x1,
29 FS_RAW_ALL = 0x2,
30 FS_RAW_PRESETS = 0x4,
31 FS_DATA_ALL = 0x8,
32 FS_DATA_PRJ = 0x10,
33 FS_DATA_SND = 0x20
34 };
35
36 gchar *elektron_get_sample_path_from_hash_size (struct backend *, guint32,
37 guint32);
38
39 GByteArray *elektron_ping (struct backend *);
40
41 gint elektron_handshake (struct backend *);
42
43 #endif
0 /*
1 * microbrute.c
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "microbrute.h"
21 #include "common.h"
22
23 #define MICROBRUTE_MAX_SEQ_STR_LEN 256
24
25 #define MICROBRUTE_MAX_SEQUENCES 8
26 #define MICROBRUTE_SEQUENCE_PREFIX "MicroBrute sequence"
27
28 #define MICROBRUTE_SEQUENCE_REQUEST_SEQ_POS 6
29 #define MICROBRUTE_SEQUENCE_REQUEST_ID_POS 9
30 #define MICROBRUTE_SEQUENCE_REQUEST_OFFSET_POS 10
31 #define MICROBRUTE_SEQUENCE_RESPONSE_LEN_POS 11
32 #define MICROBRUTE_SEQUENCE_RESPONSE_DATA_POS 12
33 #define MICROBRUTE_SEQUENCE_TXT_POS 2
34
35 static const guint8 ARTURIA_ID[] = { 0x0, 0x20, 0x6b };
36 static const guint8 FAMILY_ID[] = { 0x4, 0x0 };
37 static const guint8 MODEL_ID[] = { 0x2, 0x1 };
38
39 static const guint8 MICROBRUTE_SEQUENCE_REQUEST[] =
40 { 0xf0, 0x0, 0x20, 0x6B, 0x5, 0x1, 0x0, 0x03, 0x3B, 0x0, 0x0, 0x20, 0xf7 };
41
42 static const guint8 MICROBRUTE_SEQUENCE_MSG[] =
43 { 0xf0, 0x0, 0x20, 0x6b, 0x05, 0x01, 0x0, 0x23, 0x3a, 0x0, 0x0, 0x20,
44 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
45 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
46 0x0, 0x0, 0xf7
47 };
48
49 enum cz_fs
50 {
51 FS_MICROBRUTE_SEQUENCE = 1
52 };
53
54 static guint8
55 microbrute_get_seq (struct backend *backend)
56 {
57 guint8 *seq = backend->data;
58 guint8 value = *seq;
59 (*seq)++;
60 if (*seq == 0x80)
61 {
62 *seq = 0;
63 }
64 return value;
65 }
66
67 static gchar *
68 microbrute_get_download_path (struct backend *backend,
69 struct item_iterator *remote_iter,
70 const struct fs_operations *ops,
71 const gchar * dst_dir, const gchar * src_path)
72 {
73 gchar *name = malloc (PATH_MAX);
74 gchar *src_path_copy = strdup (src_path);
75 gchar *filename = basename (src_path_copy);
76 gint index = atoi (filename);
77 snprintf (name, PATH_MAX, "%s/%s %d.mbseq", dst_dir,
78 MICROBRUTE_SEQUENCE_PREFIX, index + 1);
79 g_free (src_path_copy);
80
81 return name;
82 }
83
84 static guint
85 microbrute_next_dentry (struct item_iterator *iter)
86 {
87 guint *next = iter->data;
88
89 if (*next >= MICROBRUTE_MAX_SEQUENCES)
90 {
91 return -ENOENT;
92 }
93
94 iter->item.id = *next;
95 snprintf (iter->item.name, LABEL_MAX, "%d", *next + 1);
96 iter->item.type = ELEKTROID_FILE;
97 iter->item.size = -1;
98 (*next)++;
99
100 return 0;
101 }
102
103 static gint
104 microbrute_read_dir (struct backend *backend, struct item_iterator *iter,
105 const gchar * path)
106 {
107 guint *next;
108
109 if (strcmp (path, "/"))
110 {
111 return -ENOTDIR;
112 }
113
114 next = g_malloc (sizeof (guint));
115 *next = 0;
116 iter->data = next;
117 iter->next = microbrute_next_dentry;
118 iter->free = g_free;
119
120 return 0;
121 }
122
123 static GByteArray *
124 microbrute_get_sequence_request_msg (struct backend *backend, guint8 id,
125 guint8 offset)
126 {
127 GByteArray *tx_msg =
128 g_byte_array_sized_new (sizeof (MICROBRUTE_SEQUENCE_REQUEST));
129 g_byte_array_append (tx_msg, MICROBRUTE_SEQUENCE_REQUEST,
130 sizeof (MICROBRUTE_SEQUENCE_REQUEST));
131 tx_msg->data[MICROBRUTE_SEQUENCE_REQUEST_SEQ_POS] =
132 microbrute_get_seq (backend);
133 tx_msg->data[MICROBRUTE_SEQUENCE_REQUEST_ID_POS] = id;
134 tx_msg->data[MICROBRUTE_SEQUENCE_REQUEST_OFFSET_POS] = offset;
135 return tx_msg;
136 }
137
138 static gint
139 microbrute_download_seq_data (struct backend *backend, guint seqnum,
140 guint offset, gchar * sequence)
141 {
142 GByteArray *tx_msg, *rx_msg;
143 gchar aux[LABEL_MAX];
144 gboolean first;
145 guint8 *step;
146
147 tx_msg = microbrute_get_sequence_request_msg (backend, seqnum, offset);
148 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, -1);
149 if (!rx_msg)
150 {
151 return -EIO;
152 }
153
154 first = offset ? FALSE : TRUE;
155 step = &rx_msg->data[MICROBRUTE_SEQUENCE_RESPONSE_DATA_POS];
156 while (*step && *step != 0xf7)
157 {
158 snprintf (aux, LABEL_MAX, "%s", first ? "" : " ");
159 strcat (sequence, aux);
160 first = FALSE;
161 if (*step == 0x7f)
162 {
163 strcat (sequence, "x");
164 }
165 else
166 {
167 snprintf (aux, LABEL_MAX, "%02d", *step);
168 strcat (sequence, aux);
169 }
170 step++;
171 }
172
173 free_msg (rx_msg);
174
175 return 0;
176 }
177
178 static gint
179 microbrute_download (struct backend *backend, const gchar * src_path,
180 GByteArray * output, struct job_control *control)
181 {
182 gchar sequence[MICROBRUTE_MAX_SEQ_STR_LEN];
183 gboolean active;
184 gchar *src_path_copy = strdup (src_path);
185 gchar *filename = basename (src_path_copy);
186 guint seqnum = atoi (filename);
187 gint err;
188
189 g_free (src_path_copy);
190
191 snprintf (sequence, MICROBRUTE_MAX_SEQ_STR_LEN, "%1d:", seqnum + 1);
192
193 control->parts = 1;
194 control->part = 0;
195 set_job_control_progress (control, 0.0);
196
197 err = microbrute_download_seq_data (backend, seqnum, 0, sequence);
198 if (err)
199 {
200 return err;
201 }
202
203 set_job_control_progress (control, 0.5);
204
205 err = microbrute_download_seq_data (backend, seqnum, 0x20, sequence);
206 if (err)
207 {
208 return err;
209 }
210
211 g_mutex_lock (&control->mutex);
212 active = control->active;
213 g_mutex_unlock (&control->mutex);
214 if (active)
215 {
216 set_job_control_progress (control, 1.0);
217 }
218 else
219 {
220 return -ECANCELED;
221 }
222
223 g_byte_array_append (output, (guint8 *) sequence, strlen (sequence));
224
225 return 0;
226 }
227
228 static GByteArray *
229 microbrute_set_sequence_request_msg (struct backend *backend, guint8 id,
230 guint8 offset)
231 {
232 GByteArray *tx_msg =
233 g_byte_array_sized_new (sizeof (MICROBRUTE_SEQUENCE_MSG));
234 g_byte_array_append (tx_msg, MICROBRUTE_SEQUENCE_MSG,
235 sizeof (MICROBRUTE_SEQUENCE_MSG));
236 tx_msg->data[MICROBRUTE_SEQUENCE_REQUEST_SEQ_POS] =
237 microbrute_get_seq (backend);
238 tx_msg->data[MICROBRUTE_SEQUENCE_REQUEST_ID_POS] = id;
239 tx_msg->data[MICROBRUTE_SEQUENCE_REQUEST_OFFSET_POS] = offset;
240 return tx_msg;
241 }
242
243 static gint
244 microbrute_send_seq_msg (struct backend *backend, guint8 seqnum,
245 guint8 offset, gchar ** tokens, gint * pos,
246 gint total)
247 {
248 struct sysex_transfer transfer;
249 guint8 steps = 0, id = seqnum;
250 gchar *token = *tokens;
251 gint err;
252 guint8 *step;
253
254 transfer.raw = microbrute_set_sequence_request_msg (backend, id, offset);
255
256 step = &transfer.raw->data[MICROBRUTE_SEQUENCE_RESPONSE_DATA_POS];
257 while (steps < 32 && *pos < total)
258 {
259 if (*token < 0x20)
260 {
261 error_print ("Invalid character\n");
262 token++;
263 (*pos)++;
264 continue;
265 }
266 else if (*token == ' ')
267 {
268 token++;
269 (*pos)++;
270 continue;
271 }
272 else if (token[0] == '0' && token[1] != ' ')
273 {
274 token++;
275 (*pos)++;
276 continue;
277 }
278 else if (*token == 'x' || *token == 'X')
279 {
280 *step = 0x7f;
281 token++;
282 (*pos)++;
283 debug_print (2, "Note: -\n");
284 }
285 else
286 {
287 gchar *rem;
288 glong note = strtol (token, &rem, 10);
289 *step = note >= 0x7f ? 0x7f : note;
290 *step = *step < 12 ? 0x7f : *step;
291 if (*step == 0 && token == rem)
292 {
293 error_print ("Error while reading note\n");
294 token++;
295 (*pos)++;
296 continue;
297 }
298 token = rem;
299 *pos += (*step >= 100) ? 3 : (*step >= 10) ? 2 : 1;
300 debug_print (2, "Note: 0x%02x (%d)\n", *step, *step);
301 }
302 steps++;
303 step++;
304 }
305 transfer.raw->data[MICROBRUTE_SEQUENCE_RESPONSE_LEN_POS] = steps;
306
307 //This doesn't need synchronized access as the caller provices this already.
308 err = backend_tx_sysex (backend, &transfer);
309 free_msg (transfer.raw);
310
311 *tokens = token;
312
313 return err < 0 ? err : steps;
314 }
315
316 static gint
317 microbrute_upload (struct backend *backend, const gchar * path,
318 GByteArray * input, struct job_control *control)
319 {
320 gchar *token = (gchar *) & input->data[MICROBRUTE_SEQUENCE_TXT_POS];
321 gint pos = MICROBRUTE_SEQUENCE_TXT_POS;
322 guint seqnum;
323 gint steps;
324
325 if (common_slot_get_id_name_from_path (path, &seqnum, NULL))
326 {
327 return -EBADSLT;
328 }
329
330 g_mutex_lock (&backend->mutex);
331
332 control->parts = 1;
333 control->part = 0;
334 set_job_control_progress (control, 0.0);
335
336 steps = microbrute_send_seq_msg (backend, seqnum, 0, &token, &pos,
337 input->len);
338 if (steps < 0)
339 {
340 goto end;
341 }
342 else if (pos < input->len)
343 {
344 set_job_control_progress (control, 0.5);
345 steps = microbrute_send_seq_msg (backend, seqnum, 0x20, &token, &pos,
346 input->len);
347 if (steps < 0)
348 {
349 goto end;
350 }
351 }
352
353 set_job_control_progress (control, 1.0);
354
355 end:
356 g_mutex_unlock (&backend->mutex);
357 return steps < 0 ? steps : 0;
358 }
359
360 static void
361 microbrute_print (struct item_iterator *iter, struct backend *backend)
362 {
363 printf ("%c %s\n", iter->item.type, iter->item.name);
364 }
365
366 static const struct fs_operations FS_MICROBRUTE_OPERATIONS = {
367 .fs = FS_MICROBRUTE_SEQUENCE,
368 .options = FS_OPTION_SINGLE_OP | FS_OPTION_ID_AS_FILENAME |
369 FS_OPTION_SLOT_STORAGE | FS_OPTION_SORT_BY_NAME,
370 .name = "sequence",
371 .gui_name = "Sequences",
372 .gui_icon = BE_FILE_ICON_SEQ,
373 .type_ext = "mbseq",
374 .readdir = microbrute_read_dir,
375 .print_item = microbrute_print,
376 .download = microbrute_download,
377 .upload = microbrute_upload,
378 .load = load_file,
379 .save = save_file,
380 .get_ext = backend_get_fs_ext,
381 .get_upload_path = common_slot_get_upload_path,
382 .get_download_path = microbrute_get_download_path
383 };
384
385 static const struct fs_operations *FS_MICROBRUTE_OPERATIONS_LIST[] = {
386 &FS_MICROBRUTE_OPERATIONS, NULL
387 };
388
389 gint
390 microbrute_handshake (struct backend *backend)
391 {
392 guint8 *seq;
393
394 if (memcmp (backend->midi_info.company, ARTURIA_ID, sizeof (ARTURIA_ID)) ||
395 memcmp (backend->midi_info.family, FAMILY_ID, sizeof (FAMILY_ID)) ||
396 memcmp (backend->midi_info.model, MODEL_ID, sizeof (MODEL_ID)))
397 {
398 return -ENODEV;
399 }
400
401 seq = malloc (sizeof (guint8));
402 *seq = 0;
403
404 backend->device_desc.filesystems = FS_MICROBRUTE_SEQUENCE;
405 backend->fs_ops = FS_MICROBRUTE_OPERATIONS_LIST;
406 backend->destroy_data = backend_destroy_data;
407 backend->data = seq;
408
409 snprintf (backend->device_name, LABEL_MAX, "Arturia MicroBrute %d.%d.%d.%d",
410 backend->midi_info.version[0], backend->midi_info.version[1],
411 backend->midi_info.version[2], backend->midi_info.version[3]);
412
413 return 0;
414 }
0 /*
1 * cz.h
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef MICROBRUTE_H
21 #define MICROBRUTE_H
22
23 #include "backend.h"
24
25 gint microbrute_handshake (struct backend *);
26
27 #endif
0 /*
1 * package.c
2 * Copyright (C) 2021 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <json-glib/json-glib.h>
23 #include "package.h"
24 #include "utils.h"
25 #include "sample.h"
26 #include "elektron.h"
27
28 #define PKG_TAG_FORMAT_VERSION "FormatVersion"
29 #define PKG_TAG_PRODUCT_TYPE "ProductType"
30 #define PKG_TAG_PAYLOAD "Payload"
31 #define PKG_TAG_FILE_TYPE "FileType"
32 #define PKG_TAG_FIRMWARE_VERSION "FirmwareVersion"
33 #define PKG_TAG_SAMPLES "Samples"
34 #define PKG_TAG_FILE_NAME "FileName"
35 #define PKG_TAG_FILE_SIZE "FileSize"
36 #define PKG_TAG_HASH "Hash"
37 #define PKG_VAL_FILE_TYPE_PRJ "Project"
38 #define PKG_VAL_FILE_TYPE_SND "Sound"
39 #define PKG_VAL_FILE_TYPE_UNK "Unknown"
40
41 #define MAN_TAG_SAMPLE_REFS "sample_references"
42 #define MAN_TAG_HASH "hash"
43 #define MAN_TAG_SIZE "size"
44
45 #define MAX_PACKAGE_LEN (64 * 1024 * 1024)
46 #define MAX_MANIFEST_LEN (128 * 1024)
47 #define MANIFEST_FILENAME "manifest.json"
48
49 const struct sample_params ELEKTRON_SAMPLE_PARAMS = {
50 .samplerate = ELEKTRON_SAMPLE_RATE,
51 .channels = ELEKTRON_SAMPLE_CHANNELS
52 };
53
54 static gint
55 package_add_resource (struct package *pkg,
56 struct package_resource *pkg_resource, gboolean new)
57 {
58 zip_source_t *sample_source;
59 zip_int64_t index;
60 zip_error_t zerror;
61
62 debug_print (1, "Adding file %s to zip (%d B)...\n", pkg_resource->path,
63 pkg_resource->data->len);
64 sample_source =
65 zip_source_buffer_create (pkg_resource->data->data,
66 pkg_resource->data->len, 0, &zerror);
67 if (!sample_source)
68 {
69 error_print ("Error while creating file source: %s\n",
70 zip_error_strerror (&zerror));
71 zip_error_fini (&zerror);
72 return -1;
73 }
74
75 index =
76 zip_file_add (pkg->zip, pkg_resource->path, sample_source,
77 ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8);
78 if (index < 0)
79 {
80 error_print ("Error while adding file: %s\n",
81 zip_error_strerror (zip_get_error (pkg->zip)));
82 zip_source_free (sample_source);
83 return -1;
84 }
85
86 if (new)
87 {
88 pkg->resources = g_list_append (pkg->resources, pkg_resource);
89 }
90
91 return 0;
92 }
93
94
95 gint
96 package_begin (struct package *pkg, gchar * name, const gchar * fw_version,
97 const struct device_desc *device_desc, enum package_type type)
98 {
99 zip_error_t zerror;
100 pkg->resources = NULL;
101 pkg->buff = g_malloc (MAX_PACKAGE_LEN);
102 pkg->name = name;
103 pkg->fw_version = strdup (fw_version);
104 pkg->device_desc = device_desc;
105 pkg->type = type;
106
107 debug_print (1, "Creating zip buffer...\n");
108
109 zip_error_init (&zerror);
110 pkg->zip_source =
111 zip_source_buffer_create (pkg->buff, MAX_PACKAGE_LEN, 0, &zerror);
112 if (!pkg->zip_source)
113 {
114 error_print ("Error while creating zip source: %s\n",
115 zip_error_strerror (&zerror));
116 zip_error_fini (&zerror);
117 g_free (pkg->buff);
118 return -1;
119 }
120
121 pkg->zip = zip_open_from_source (pkg->zip_source, ZIP_TRUNCATE, &zerror);
122 if (!pkg->zip)
123 {
124 error_print ("Error while creating in memory zip: %s\n",
125 zip_error_strerror (&zerror));
126 zip_error_fini (&zerror);
127 zip_source_free (pkg->zip_source);
128 g_free (pkg->buff);
129 return -1;
130 }
131
132 zip_source_keep (pkg->zip_source);
133
134 pkg->manifest = g_malloc (sizeof (struct package_resource));
135 pkg->manifest->type = PKG_RES_TYPE_MANIFEST;
136 pkg->manifest->data = g_byte_array_sized_new (MAX_MANIFEST_LEN); //We need this because we can not resize later.
137 pkg->manifest->path = strdup (MANIFEST_FILENAME);
138 package_add_resource (pkg, pkg->manifest, TRUE);
139
140 return 0;
141 }
142
143 static gint
144 package_add_manifest (struct package *pkg)
145 {
146 JsonBuilder *builder;
147 JsonGenerator *gen;
148 JsonNode *root;
149 gchar *json;
150 gint len;
151 gchar *val = g_malloc (LABEL_MAX);
152 GList *resource;
153 gboolean samples_found = FALSE;
154 struct package_resource *pkg_resource;
155
156 builder = json_builder_new ();
157
158 json_builder_begin_object (builder);
159
160 json_builder_set_member_name (builder, PKG_TAG_FORMAT_VERSION);
161 json_builder_add_string_value (builder, "1.0");
162
163 json_builder_set_member_name (builder, PKG_TAG_PRODUCT_TYPE);
164 json_builder_begin_array (builder);
165 snprintf (val, LABEL_MAX, "%d", pkg->device_desc->id);
166 json_builder_add_string_value (builder, val);
167 json_builder_end_array (builder);
168
169 json_builder_set_member_name (builder, PKG_TAG_PAYLOAD);
170 json_builder_add_string_value (builder, pkg->name);
171
172 json_builder_set_member_name (builder, PKG_TAG_FILE_TYPE);
173 json_builder_add_string_value (builder,
174 pkg->type & PKG_FILE_TYPE_SOUND ?
175 PKG_VAL_FILE_TYPE_SND : pkg->type &
176 PKG_FILE_TYPE_PROJECT ? PKG_VAL_FILE_TYPE_PRJ
177 : PKG_VAL_FILE_TYPE_UNK);
178
179 if (pkg->type != PKG_FILE_TYPE_PRESET)
180 {
181 json_builder_set_member_name (builder, PKG_TAG_FIRMWARE_VERSION);
182 json_builder_add_string_value (builder, pkg->fw_version);
183 }
184
185 if (pkg->device_desc->filesystems & FS_SAMPLES)
186 {
187 for (resource = pkg->resources; resource; resource = resource->next)
188 {
189 pkg_resource = resource->data;
190 if (pkg_resource->type == PKG_RES_TYPE_SAMPLE)
191 {
192 samples_found = TRUE;
193 break;
194 }
195 }
196 }
197
198 if (samples_found)
199 {
200 json_builder_set_member_name (builder, PKG_TAG_SAMPLES);
201 json_builder_begin_array (builder);
202 for (resource = pkg->resources; resource; resource = resource->next)
203 {
204 pkg_resource = resource->data;
205 if (pkg_resource->type == PKG_RES_TYPE_SAMPLE)
206 {
207 json_builder_begin_object (builder);
208
209 json_builder_set_member_name (builder, PKG_TAG_FILE_NAME);
210 json_builder_add_string_value (builder, pkg_resource->path);
211
212 json_builder_set_member_name (builder, PKG_TAG_FILE_SIZE);
213 json_builder_add_int_value (builder, pkg_resource->size);
214
215 json_builder_set_member_name (builder, PKG_TAG_HASH);
216 snprintf (val, LABEL_MAX, "%d", pkg_resource->hash);
217 json_builder_add_string_value (builder, val);
218
219 json_builder_end_object (builder);
220 }
221 }
222 json_builder_end_array (builder);
223 }
224
225 json_builder_end_object (builder);
226
227 gen = json_generator_new ();
228 g_object_set (gen, "pretty", TRUE, NULL);
229 root = json_builder_get_root (builder);
230 json_generator_set_root (gen, root);
231 json = json_generator_to_data (gen, NULL);
232
233 len = strlen (json);
234 memcpy (pkg->manifest->data->data, json, len);
235 pkg->manifest->data->len = len;
236 package_add_resource (pkg, pkg->manifest, FALSE);
237
238 g_free (json);
239 json_node_free (root);
240 g_object_unref (gen);
241 g_object_unref (builder);
242 g_free (val);
243
244 return 0;
245 }
246
247 gint
248 package_end (struct package *pkg, GByteArray * out)
249 {
250 int ret = 0;
251 zip_stat_t zstat;
252
253 ret = package_add_manifest (pkg);
254 if (ret)
255 {
256 error_print ("Error while formatting %s\n", MANIFEST_FILENAME);
257 return ret;
258 }
259
260 debug_print (1, "Writing zip to buffer...\n");
261 if (zip_close (pkg->zip))
262 {
263 error_print ("Error while creating in memory zip: %s\n",
264 zip_error_strerror (zip_get_error (pkg->zip)));
265 return -1;
266 }
267
268 zip_source_stat (pkg->zip_source, &zstat);
269 debug_print (1, "%" PRIu64 " B written to package\n", zstat.comp_size);
270
271 zip_source_open (pkg->zip_source);
272 g_byte_array_set_size (out, zstat.comp_size);
273 zip_source_read (pkg->zip_source, out->data, zstat.comp_size);
274 zip_source_close (pkg->zip_source);
275
276 return 0;
277 }
278
279 void
280 package_free_package_resource (gpointer data)
281 {
282 struct package_resource *pkg_resource = data;
283 g_byte_array_free (pkg_resource->data, TRUE);
284 g_free (pkg_resource);
285 }
286
287 void
288 package_destroy (struct package *pkg)
289 {
290 zip_source_free (pkg->zip_source);
291 g_free (pkg->buff);
292 g_free (pkg->name);
293 g_free (pkg->fw_version);
294 g_list_free_full (pkg->resources, package_free_package_resource);
295 }
296
297 gint
298 package_open (struct package *pkg, GByteArray * data,
299 const struct device_desc *device_desc)
300 {
301 gint ret;
302 zip_error_t zerror;
303 zip_file_t *manifest_file;
304 zip_stat_t zstat;
305
306 debug_print (1, "Opening zip stream...\n");
307
308 zip_error_init (&zerror);
309 pkg->zip_source =
310 zip_source_buffer_create (data->data, data->len, 0, &zerror);
311 if (!pkg->zip_source)
312 {
313 error_print ("Error while creating zip source: %s\n",
314 zip_error_strerror (&zerror));
315 zip_error_fini (&zerror);
316 return -1;
317 }
318
319 pkg->zip = zip_open_from_source (pkg->zip_source, ZIP_RDONLY, &zerror);
320 if (!pkg->zip)
321 {
322 error_print ("Error while creating in memory zip: %s\n",
323 zip_error_strerror (&zerror));
324 zip_error_fini (&zerror);
325 zip_source_free (pkg->zip_source);
326 return -1;
327 }
328
329 ret = zip_stat (pkg->zip, MANIFEST_FILENAME, ZIP_FL_ENC_STRICT, &zstat);
330 if (ret)
331 {
332 error_print ("Error while loading '%s': %s\n", MANIFEST_FILENAME,
333 zip_error_strerror (&zerror));
334 zip_error_fini (&zerror);
335 zip_source_free (pkg->zip_source);
336 zip_close (pkg->zip);
337 return -1;
338 }
339
340 pkg->manifest = g_malloc (sizeof (struct package_resource));
341 pkg->manifest->type = PKG_RES_TYPE_MANIFEST;
342 pkg->manifest->data = g_byte_array_sized_new (zstat.size);
343 pkg->manifest->path = strdup (MANIFEST_FILENAME);
344 manifest_file = zip_fopen (pkg->zip, MANIFEST_FILENAME, 0);
345 zip_fread (manifest_file, pkg->manifest->data->data, zstat.size);
346 pkg->manifest->data->len = zstat.size;
347 zip_fclose (manifest_file);
348
349 pkg->resources = NULL;
350 pkg->resources = g_list_append (pkg->resources, pkg->manifest);
351 pkg->buff = NULL;
352 pkg->name = NULL;
353 pkg->fw_version = NULL;
354 pkg->device_desc = device_desc;
355
356 return ret;
357 }
358
359 void
360 package_close (struct package *pkg)
361 {
362 zip_source_close (pkg->zip_source);
363 package_destroy (pkg);
364 }
365
366 gint
367 package_receive_pkg_resources (struct package *pkg,
368 const gchar * payload_path,
369 struct job_control *control,
370 struct backend *backend,
371 fs_remote_file_op download_data,
372 fs_remote_file_op download_sample)
373 {
374 gint ret, i, elements;
375 JsonParser *parser;
376 JsonReader *reader;
377 gint64 hash, size;
378 GError *error;
379 gchar *sample_path, *metadata_path;
380 struct package_resource *pkg_resource;
381 GByteArray *wave, *payload, *metadata, *sample;
382
383 metadata_path = chain_path (payload_path, ".metadata");
384 debug_print (1, "Getting metadata from %s...\n", metadata_path);
385 metadata = g_byte_array_new ();
386 control->parts = 130; // 128 sample slots, metadata and main.
387 control->part = 0;
388 set_job_control_progress (control, 0.0);
389 ret = download_data (backend, metadata_path, metadata, control);
390 if (ret)
391 {
392 debug_print (1, "Metadata file not available\n");
393 control->parts = 1;
394 goto get_payload;
395 }
396
397 control->part++;
398
399 parser = json_parser_new ();
400 if (!json_parser_load_from_data
401 (parser, (gchar *) metadata->data, metadata->len, &error))
402 {
403 error_print ("Unable to parse stream: %s. Continuing...",
404 error->message);
405 g_clear_error (&error);
406 control->parts = 2;
407 goto get_payload;
408 }
409
410 reader = json_reader_new (json_parser_get_root (parser));
411 if (!reader)
412 {
413 error_print ("Unable to read from parser. Continuing...");
414 control->parts = 2;
415 goto get_payload;
416 }
417
418 if (!json_reader_read_member (reader, MAN_TAG_SAMPLE_REFS))
419 {
420 debug_print (1, "Member '%s' not found\n", MAN_TAG_SAMPLE_REFS);
421 control->parts = 2;
422 goto get_payload;
423 }
424
425 if (!json_reader_is_array (reader))
426 {
427 error_print ("Member '%s' is not an array. Continuing...\n",
428 MAN_TAG_SAMPLE_REFS);
429 control->parts = 2;
430 goto cleanup_reader;
431 }
432
433 elements = json_reader_count_elements (reader);
434 if (!elements)
435 {
436 debug_print (1, "No samples found\n");
437 control->parts = 2;
438 goto cleanup_reader;
439 }
440
441 sample = g_byte_array_new ();
442 control->parts = 2 + elements;
443 set_job_control_progress (control, 0.0);
444 for (i = 0; i < elements; i++, control->part++)
445 {
446 if (!json_reader_read_element (reader, i))
447 {
448 error_print ("Cannot read element %d. Continuing...\n", i);
449 continue;
450 }
451 if (!json_reader_read_member (reader, MAN_TAG_HASH))
452 {
453 error_print ("Cannot read member '%s'. Continuing...\n",
454 MAN_TAG_HASH);
455 continue;
456 }
457 hash = json_reader_get_int_value (reader);
458 json_reader_end_element (reader);
459
460 if (!json_reader_read_member (reader, MAN_TAG_SIZE))
461 {
462 error_print ("Cannot read member '%s'. Continuing...\n",
463 MAN_TAG_SIZE);
464 continue;
465 }
466 size = json_reader_get_int_value (reader);
467 json_reader_end_element (reader);
468
469 json_reader_end_element (reader);
470
471 sample_path = elektron_get_sample_path_from_hash_size (backend, hash,
472 size);
473 if (!sample_path)
474 {
475 debug_print (1, "Sample not found. Skipping...\n");
476 continue;
477 }
478
479 debug_print (1, "Hash: %" PRIu64 "; size: %" PRIu64 "; path: %s\n",
480 hash, size, sample_path);
481 debug_print (1, "Getting sample %s...\n", sample_path);
482 g_byte_array_set_size (sample, 0);
483 if (download_sample (backend, sample_path, sample, control))
484 {
485 g_free (sample_path);
486 error_print ("Error while downloading sample. Continuing...\n");
487 continue;
488 }
489
490 wave = g_byte_array_new ();
491 ret = sample_get_wav_from_array (sample, wave, control);
492 if (ret)
493 {
494 error_print
495 ("Error while converting sample to wave file. Continuing...\n");
496 g_byte_array_free (wave, TRUE);
497 g_free (sample_path);
498 continue;
499 }
500
501 pkg_resource = g_malloc (sizeof (struct package_resource));
502 pkg_resource->type = PKG_RES_TYPE_SAMPLE;
503 pkg_resource->data = wave;
504 pkg_resource->hash = hash;
505 pkg_resource->size = size;
506 pkg_resource->path = g_malloc (PATH_MAX);
507 snprintf (pkg_resource->path, PATH_MAX, "%s%s.wav", PKG_TAG_SAMPLES,
508 sample_path);
509 if (package_add_resource (pkg, pkg_resource, TRUE))
510 {
511 package_free_package_resource (pkg_resource);
512 error_print ("Error while packaging sample\n");
513 continue;
514 }
515 }
516
517 g_byte_array_free (sample, TRUE);
518 cleanup_reader:
519 g_object_unref (reader);
520 g_object_unref (parser);
521 get_payload:
522 g_byte_array_free (metadata, TRUE);
523 debug_print (1, "Getting payload from %s...\n", payload_path);
524 payload = g_byte_array_new ();
525 ret = download_data (backend, payload_path, payload, control);
526 if (ret)
527 {
528 error_print ("Error while downloading payload\n");
529 ret = -1;
530 }
531 else
532 {
533 pkg_resource = g_malloc (sizeof (struct package_resource));
534 pkg_resource->type = PKG_RES_TYPE_PAYLOAD;
535 pkg_resource->data = payload;
536 pkg_resource->path = strdup (pkg->name);
537 if (package_add_resource (pkg, pkg_resource, TRUE))
538 {
539 package_free_package_resource (pkg_resource);
540 ret = -1;
541 }
542 }
543 return ret;
544 }
545
546 gint
547 package_send_pkg_resources (struct package *pkg,
548 const gchar * payload_path,
549 struct job_control *control,
550 struct backend *backend,
551 fs_remote_file_op upload_data,
552 fs_remote_file_op upload_sample)
553 {
554 gint elements, i, ret = 0;
555 const gchar *file_type, *sample_path;
556 gint64 product_type;
557 JsonParser *parser;
558 JsonReader *reader;
559 GError *error;
560 zip_stat_t zstat;
561 zip_error_t zerror;
562 zip_file_t *zip_file;
563 GByteArray *wave, *raw;
564 struct package_resource *pkg_resource;
565
566 zip_error_init (&zerror);
567
568 parser = json_parser_new ();
569 if (!json_parser_load_from_data
570 (parser, (gchar *) pkg->manifest->data->data, pkg->manifest->data->len,
571 &error))
572 {
573 error_print ("Unable to parse stream: %s", error->message);
574 g_clear_error (&error);
575 ret = -1;
576 goto cleanup_parser;
577 }
578
579 reader = json_reader_new (json_parser_get_root (parser));
580 if (!reader)
581 {
582 ret = -1;
583 goto cleanup_parser;
584 }
585
586 if (!json_reader_read_member (reader, PKG_TAG_PAYLOAD))
587 {
588 error_print ("No '%s' found\n", PKG_TAG_PAYLOAD);
589 ret = -1;
590 goto cleanup_reader;
591 }
592 pkg->name = strdup (json_reader_get_string_value (reader));
593 json_reader_end_element (reader);
594
595 if (zip_stat (pkg->zip, pkg->name, ZIP_FL_ENC_STRICT, &zstat))
596 {
597 error_print ("Error while loading '%s': %s\n", MANIFEST_FILENAME,
598 zip_error_strerror (&zerror));
599 zip_error_fini (&zerror);
600 ret = -1;
601 goto cleanup_reader;
602 }
603
604 pkg_resource = g_malloc (sizeof (struct package_resource));
605 pkg_resource->type = PKG_RES_TYPE_PAYLOAD;
606 pkg_resource->data = g_byte_array_sized_new (zstat.size);
607 pkg_resource->path = strdup (pkg->name);
608 zip_file = zip_fopen (pkg->zip, pkg->name, 0);
609 zip_fread (zip_file, pkg_resource->data->data, zstat.size);
610 pkg_resource->data->len = zstat.size;
611 zip_fclose (zip_file);
612
613 pkg->resources = g_list_append (pkg->resources, pkg_resource);
614
615 control->parts = 129; // 128 sample slots and main.
616 control->part = 0;
617 ret = upload_data (backend, payload_path, pkg_resource->data, control);
618 if (ret)
619 {
620 error_print ("Error while uploading payload to '%s'\n", payload_path);
621 goto cleanup_reader;
622 }
623 control->part++;
624
625 if (!json_reader_read_member (reader, PKG_TAG_FIRMWARE_VERSION))
626 {
627 error_print ("No '%s' found\n", PKG_TAG_FIRMWARE_VERSION);
628 ret = -1;
629 goto cleanup_reader;
630 }
631 pkg->fw_version = strdup (json_reader_get_string_value (reader));
632 json_reader_end_element (reader);
633
634 if (!json_reader_read_member (reader, PKG_TAG_FILE_TYPE))
635 {
636 error_print ("No '%s' found\n", PKG_TAG_FILE_TYPE);
637 ret = -1;
638 goto cleanup_reader;
639 }
640 file_type = json_reader_get_string_value (reader);
641 json_reader_end_element (reader);
642
643 if (strcmp (file_type, PKG_VAL_FILE_TYPE_SND) == 0)
644 {
645 pkg->type = PKG_FILE_TYPE_SOUND;
646 }
647 else if (strcmp (file_type, PKG_VAL_FILE_TYPE_PRJ) == 0)
648 {
649 pkg->type = PKG_FILE_TYPE_PROJECT;
650 }
651 else
652 {
653 pkg->type = PKG_FILE_TYPE_NONE;
654 debug_print (1, "Invalid '%s': %s\n", PKG_TAG_FILE_TYPE, file_type);
655 }
656
657 if (!json_reader_read_member (reader, PKG_TAG_PRODUCT_TYPE))
658 {
659 error_print ("No '%s' found\n", PKG_TAG_PRODUCT_TYPE);
660 ret = 0;
661 goto cleanup_reader;
662 }
663 if (!json_reader_is_array (reader))
664 {
665 error_print ("Member '%s' is not an array\n", PKG_TAG_PRODUCT_TYPE);
666 ret = -1;
667 goto cleanup_reader;
668 }
669 if (!json_reader_count_elements (reader))
670 {
671 error_print ("No product types found\n");
672 ret = 0;
673 goto cleanup_reader;
674 }
675 if (!json_reader_read_element (reader, 0))
676 {
677 ret = -1;
678 goto cleanup_reader;
679 }
680 product_type = atoi (json_reader_get_string_value (reader));
681 debug_print (1, "ProductType: %" PRId64 "\n", product_type);
682 if (pkg->device_desc->id != product_type)
683 {
684 debug_print (1, "Incompatible product type. Continuing...\n");
685 }
686 json_reader_end_element (reader);
687 json_reader_end_element (reader);
688
689 if (!json_reader_read_member (reader, PKG_TAG_SAMPLES))
690 {
691 if (pkg->device_desc->filesystems & FS_SAMPLES)
692 {
693 debug_print (1, "No samples found\n");
694 }
695 control->parts = 1; // Only payload and it's done.
696 control->part = 0;
697 set_job_control_progress (control, 1.0);
698 goto cleanup_reader;
699 }
700
701 if (!json_reader_is_array (reader))
702 {
703 error_print ("Member '%s' is not an array. Skipping samples...\n",
704 PKG_TAG_SAMPLES);
705 ret = -1;
706 goto cleanup_reader;
707 }
708
709 wave = g_byte_array_sized_new (zstat.size);
710 raw = g_byte_array_sized_new (MAX_PACKAGE_LEN);
711 elements = json_reader_count_elements (reader);
712 control->parts = elements + 1;
713 control->part = 1;
714 for (i = 0; i < elements; i++, control->part++)
715 {
716 guint frames;
717
718 json_reader_read_element (reader, i);
719 json_reader_read_member (reader, PKG_TAG_FILE_NAME);
720 sample_path = json_reader_get_string_value (reader);
721 json_reader_end_element (reader);
722 json_reader_end_element (reader);
723
724 if (zip_stat (pkg->zip, sample_path, ZIP_FL_ENC_STRICT, &zstat))
725 {
726 error_print ("Error while loading '%s': %s\n",
727 MANIFEST_FILENAME, zip_error_strerror (&zerror));
728 zip_error_fini (&zerror);
729 ret = -1;
730 continue;
731 }
732
733 g_byte_array_set_size (wave, zstat.size);
734 zip_file = zip_fopen (pkg->zip, sample_path, 0);
735 zip_fread (zip_file, wave->data, zstat.size);
736 wave->len = zstat.size;
737 zip_fclose (zip_file);
738
739 raw->len = 0;
740 if (sample_load_from_array (wave, raw, control,
741 &ELEKTRON_SAMPLE_PARAMS, &frames))
742 {
743 error_print ("Error while loading '%s': %s\n",
744 sample_path, zip_error_strerror (&zerror));
745 continue;
746 }
747
748 pkg_resource = g_malloc (sizeof (struct package_resource));
749 pkg_resource->type = PKG_RES_TYPE_SAMPLE;
750 pkg_resource->data = g_byte_array_sized_new (raw->len);
751 pkg_resource->data->len = raw->len;
752 memcpy (pkg_resource->data->data, raw->data, raw->len);
753 pkg_resource->path = strdup (sample_path);
754
755 pkg->resources = g_list_append (pkg->resources, pkg_resource);
756
757 //We remove the "Samples" at the beggining of the full zip path.
758 ret = upload_sample (backend, &sample_path[7], pkg_resource->data,
759 control);
760 g_free (control->data);
761 control->data = NULL;
762 if (ret)
763 {
764 error_print ("Error while uploading sample to '%s'\n",
765 &sample_path[7]);
766 continue;
767 }
768 }
769
770 g_byte_array_free (wave, TRUE);
771 g_byte_array_free (raw, TRUE);
772
773 cleanup_reader:
774 g_object_unref (reader);
775 cleanup_parser:
776 g_object_unref (parser);
777 return ret;
778 }
0 /*
1 * package.h
2 * Copyright (C) 2021 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <glib.h>
21 #include <zip.h>
22 #include "backend.h"
23
24 #ifndef PACKAGE_H
25 #define PACKAGE_H
26
27 #define ELEKTRON_SAMPLE_RATE 48000
28 #define ELEKTRON_SAMPLE_CHANNELS 1
29
30 enum package_resource_type
31 {
32 PKG_RES_TYPE_NONE,
33 PKG_RES_TYPE_PAYLOAD,
34 PKG_RES_TYPE_MANIFEST,
35 PKG_RES_TYPE_SAMPLE
36 };
37
38 struct package_resource
39 {
40 enum package_resource_type type;
41 guint32 hash;
42 guint32 size;
43 gchar *path;
44 GByteArray *data;
45 };
46
47 enum package_type
48 {
49 PKG_FILE_TYPE_NONE,
50 PKG_FILE_TYPE_SOUND,
51 PKG_FILE_TYPE_PROJECT,
52 PKG_FILE_TYPE_PRESET,
53 };
54
55 struct package
56 {
57 gchar *name;
58 enum package_type type;
59 gchar *fw_version;
60 const struct device_desc *device_desc;
61 gchar *buff;
62 zip_source_t *zip_source;
63 zip_t *zip;
64 GList *resources;
65 struct package_resource *manifest;
66 };
67
68 gint package_begin (struct package *, gchar *, const gchar *,
69 const struct device_desc *, enum package_type);
70
71 gint package_receive_pkg_resources (struct package *, const gchar *,
72 struct job_control *, struct backend *,
73 fs_remote_file_op, fs_remote_file_op);
74
75 gint package_end (struct package *, GByteArray *);
76
77 void package_destroy (struct package *);
78
79 gint package_open (struct package *, GByteArray *,
80 const struct device_desc *);
81
82 gint package_send_pkg_resources (struct package *,
83 const gchar *,
84 struct job_control *,
85 struct backend *, fs_remote_file_op,
86 fs_remote_file_op);
87
88 void package_close (struct package *);
89
90 extern const struct sample_params ELEKTRON_SAMPLE_PARAMS;
91
92 #endif
0 /*
1 * sds.c
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <math.h>
21 #include <string.h>
22 #include <glib/gi18n.h>
23 #include "elektron.h"
24 #include "sample.h"
25 #include "sds.h"
26 #include "common.h"
27
28 #define SDS_SAMPLE_LIMIT 1000
29 #define SDS_DATA_PACKET_LEN 127
30 #define SDS_DATA_PACKET_PAYLOAD_LEN 120
31 #define SDS_DATA_PACKET_CKSUM_POS 125
32 #define SDS_DATA_PACKET_CKSUM_START 1
33 #define SDS_BYTES_PER_WORD 3
34 #define SDS_MAX_RETRIES 3
35 #define SDS_SPEC_TIMEOUT 20 //Timeout in the specs to consider no response when transmission is going on.
36 #define SDS_SPEC_TIMEOUT_HANDSHAKE 2000 //Timeout in the specs to consider no response during the handshake.
37 #define SDS_NO_SPEC_TIMEOUT 5000 //Timeout used when the specs indicate to wait indefinitely.
38 #define SDS_NO_SPEC_TIMEOUT_TRY 1500 //Timeout for SDS extensions that might not be implemented.
39 #define SDS_REST_TIME_DEFAULT 18000 //Rest time to not overwhelm the devices whn sending consecutive packets. Lower values cause an an E-Mu ESI-2000 to send corrupted packets.
40 #define SDS_NO_SPEC_OPEN_LOOP_REST_TIME 200000
41 #define SDS_SAMPLE_CHANNELS 1
42 #define SDS_SAMPLE_NAME_MAX_LEN 127
43
44 struct sds_data
45 {
46 gint rest_time;
47 gboolean name_extension;
48 };
49
50 static const guint8 SDS_SAMPLE_REQUEST[] = { 0xf0, 0x7e, 0, 0x3, 0, 0, 0xf7 };
51 static const guint8 SDS_ACK[] = { 0xf0, 0x7e, 0, 0x7f, 0, 0xf7 };
52 static const guint8 SDS_NAK[] = { 0xf0, 0x7e, 0, 0x7e, 0, 0xf7 };
53 static const guint8 SDS_CANCEL[] = { 0xf0, 0x7e, 0, 0x7d, 0, 0xf7 };
54 static const guint8 SDS_WAIT[] = { 0xf0, 0x7e, 0, 0x7c, 0, 0xf7 };
55 static const guint8 SDS_SAMPLE_NAME_REQUEST[] =
56 { 0xf0, 0x7e, 0, 0x5, 0x4, 0, 0, 0xf7 };
57 static const guint8 SDS_DATA_PACKET_HEADER[] = { 0xf0, 0x7e, 0, 0x2, 0 };
58 static const guint8 SDS_SAMPLE_NAME_HEADER[] =
59 { 0xf0, 0x7e, 0, 0x5, 0x3, 0, 0, 0 };
60 static const guint8 SDS_DUMP_HEADER[] =
61 { 0xf0, 0x7e, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf7 };
62
63 static gchar *
64 sds_get_download_path (struct backend *backend,
65 struct item_iterator *remote_iter,
66 const struct fs_operations *ops, const gchar * dst_dir,
67 const gchar * src_path)
68 {
69 GByteArray *tx_msg, *rx_msg;
70 gchar *name = malloc (PATH_MAX);
71 gchar *src_path_copy = strdup (src_path);
72 gchar *filename = basename (src_path_copy);
73 gint index = atoi (filename);
74 gboolean use_id = TRUE;
75 struct sds_data *sds_data = backend->data;
76
77 if (sds_data->name_extension)
78 {
79 g_mutex_lock (&backend->mutex);
80 backend_rx_drain (backend);
81 g_mutex_unlock (&backend->mutex);
82
83 tx_msg = g_byte_array_new ();
84 g_byte_array_append (tx_msg, SDS_SAMPLE_NAME_REQUEST,
85 sizeof (SDS_SAMPLE_NAME_REQUEST));
86 tx_msg->data[5] = index % 0x80;
87 tx_msg->data[6] = index / 0x80;
88 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT);
89 if (rx_msg)
90 {
91 snprintf (name, PATH_MAX, "%s/%s.wav", dst_dir, &rx_msg->data[5]);
92 free_msg (rx_msg);
93 use_id = FALSE;
94 }
95 }
96
97 if (use_id)
98 {
99 snprintf (name, PATH_MAX, "%s/%03d.wav", dst_dir, index);
100 }
101
102 g_free (src_path_copy);
103 return name;
104 }
105
106 static guint
107 sds_get_bytes_value_right_just (guint8 * data, gint length)
108 {
109 gint value = 0;
110 for (gint i = 0, shift = 0; i < length; i++, shift += 7)
111 {
112 value |= data[i] << shift;
113 }
114 return value;
115 }
116
117 static void
118 sds_set_bytes_value_right_just (guint8 * data, gint length, guint value)
119 {
120 for (gint i = 0, shift = 0; i < length; i++, shift += 7)
121 {
122 *data = 0x7f & (value >> shift);
123 data++;
124 }
125 }
126
127 static gint16
128 sds_get_gint16_value_left_just (guint8 * data, gint length, guint bits)
129 {
130 guint value = 0;
131 gint16 svalue;
132 for (gint i = length - 1, shift = 0; i >= 0; i--, shift += 7)
133 {
134 value |= (((guint) data[i]) << shift);
135 }
136 value >>= length * 7 - bits;
137 svalue = (gint16) (value - 0x8000);
138 return svalue;
139 }
140
141 static void
142 sds_set_gint16_value_left_just (guint8 * data, gint length, guint bits,
143 gint16 svalue)
144 {
145 gint value = svalue;
146 value += (guint) 0x8000;
147 value <<= length * 7 - bits;
148 for (gint i = length - 1, shift = 0; i >= 0; i--, shift += 7)
149 {
150 data[i] = (guint8) (0x7f & (value >> shift));
151 }
152 }
153
154 static guint8
155 sds_checksum (guint8 * data)
156 {
157 guint8 checksum = 0;
158 for (int i = SDS_DATA_PACKET_CKSUM_START; i < SDS_DATA_PACKET_CKSUM_POS;
159 i++)
160 {
161 checksum ^= data[i];
162 }
163 checksum &= 0x7F;
164 return checksum;
165 }
166
167 static gint
168 sds_get_bytes_per_word (gint32 bits, guint * word_size,
169 guint * bytes_per_word)
170 {
171 *word_size = (guint) ceil (bits / 8.0);
172 if (*word_size != 2)
173 {
174 error_print ("%d bits resolution not supported\n", bits);
175 return -1;
176 }
177
178 if (bits < 15)
179 {
180 *bytes_per_word = 2;
181 }
182 else
183 {
184 *bytes_per_word = 3;
185 }
186
187 return 0;
188 }
189
190 static gint
191 sds_tx (struct backend *backend, GByteArray * tx_msg)
192 {
193 struct sysex_transfer transfer;
194 transfer.raw = tx_msg;
195 g_mutex_lock (&backend->mutex);
196 backend_tx_sysex (backend, &transfer);
197 g_mutex_unlock (&backend->mutex);
198 free_msg (tx_msg);
199 return transfer.err;
200 }
201
202 static gint
203 sds_tx_handshake (struct backend *backend, const guint8 * msg, guint8 packet)
204 {
205 GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SDS_ACK));
206 g_byte_array_append (tx_msg, msg, sizeof (SDS_ACK));
207 tx_msg->data[4] = packet;
208 return sds_tx (backend, tx_msg);
209 }
210
211 static guint
212 sds_get_download_info (GByteArray * header, struct sample_info *sample_info,
213 guint * words, guint * word_size,
214 guint * bytes_per_word)
215 {
216 sample_info->bitdepth = header->data[6];
217 if (sds_get_bytes_per_word (sample_info->bitdepth, word_size,
218 bytes_per_word))
219 {
220 return -1;
221 }
222 sample_info->samplerate =
223 1.0e9 / sds_get_bytes_value_right_just (&header->data[7],
224 SDS_BYTES_PER_WORD);
225 *words =
226 sds_get_bytes_value_right_just (&header->data[10], SDS_BYTES_PER_WORD);
227 sample_info->loopstart =
228 sds_get_bytes_value_right_just (&header->data[13], SDS_BYTES_PER_WORD);
229 sample_info->loopend =
230 sds_get_bytes_value_right_just (&header->data[16], SDS_BYTES_PER_WORD);
231 sample_info->looptype = header->data[19];
232 sample_info->channels = 1;
233 return 0;
234 }
235
236 static inline gboolean
237 sds_check_message_id (GByteArray * msg, guint id)
238 {
239 return (msg->data[4] == id % 0x80 && msg->data[5] == id / 0x80);
240 }
241
242 static inline void
243 sds_set_message_id (GByteArray * tx_msg, guint id)
244 {
245 tx_msg->data[4] = id % 0x80;
246 tx_msg->data[5] = id / 0x80;
247 }
248
249 static GByteArray *
250 sds_get_request_msg (guint id)
251 {
252 GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SDS_SAMPLE_REQUEST));
253 g_byte_array_append (tx_msg, SDS_SAMPLE_REQUEST,
254 sizeof (SDS_SAMPLE_REQUEST));
255 sds_set_message_id (tx_msg, id);
256 return tx_msg;
257 }
258
259 static GByteArray *
260 sds_get_dump_msg (guint id, guint frames, struct sample_info *sample_info,
261 guint bits)
262 {
263 guint period;
264 GByteArray *tx_msg = g_byte_array_sized_new (sizeof (SDS_DUMP_HEADER));
265 g_byte_array_append (tx_msg, SDS_DUMP_HEADER, sizeof (SDS_DUMP_HEADER));
266 sds_set_message_id (tx_msg, id);
267
268 if (sample_info)
269 {
270 tx_msg->data[6] = (guint8) bits;
271 period = 1.0e9 / sample_info->samplerate;
272 sds_set_bytes_value_right_just (&tx_msg->data[7], SDS_BYTES_PER_WORD,
273 period);
274 sds_set_bytes_value_right_just (&tx_msg->data[10], SDS_BYTES_PER_WORD,
275 frames);
276 sds_set_bytes_value_right_just (&tx_msg->data[13], SDS_BYTES_PER_WORD,
277 sample_info->loopstart);
278 sds_set_bytes_value_right_just (&tx_msg->data[16], SDS_BYTES_PER_WORD,
279 sample_info->loopend);
280 tx_msg->data[19] = (sample_info->loopstart == sample_info->loopend
281 && sample_info->loopstart ==
282 frames - 1) ? 0x7f : sample_info->looptype;
283 }
284
285 return tx_msg;
286 }
287
288 static GByteArray *
289 sds_rx (struct backend *backend, gint timeout)
290 {
291 struct sysex_transfer transfer;
292 transfer.timeout = timeout;
293 transfer.batch = FALSE;
294 g_mutex_lock (&backend->mutex);
295 backend_rx_sysex (backend, &transfer);
296 g_mutex_unlock (&backend->mutex);
297 return transfer.raw;
298 }
299
300 static void
301 sds_download_inc_packet (gboolean * first, guint * packet)
302 {
303 if (*first)
304 {
305 *first = FALSE;
306 }
307 else
308 {
309 (*packet)++;
310 }
311 }
312
313 static void
314 sds_debug_print_sample_data (guint bitdepth, guint bytes_per_word,
315 guint word_size, guint sample_rate, guint words,
316 guint packets)
317 {
318 debug_print (1,
319 "Resolution: %d bits; %d bytes per word; word size %d bytes.\n",
320 bitdepth, bytes_per_word, word_size);
321 debug_print (1, "Sample rate: %d Hz\n", sample_rate);
322 debug_print (1, "Words: %d\n", words);
323 debug_print (1, "Packets: %d\n", packets);
324 }
325
326 static GByteArray *
327 sds_download_get_header (struct backend *backend, guint id)
328 {
329 GByteArray *tx_msg, *rx_msg;
330
331 tx_msg = sds_get_request_msg (id);
332 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT);
333
334 if (rx_msg && rx_msg->len == sizeof (SDS_DUMP_HEADER)
335 && !memcmp (rx_msg->data, SDS_DUMP_HEADER, 4)
336 && sds_check_message_id (rx_msg, id))
337 {
338 return rx_msg;
339 }
340
341 debug_print (1, "Bad dump header\n");
342
343 return NULL;
344 }
345
346 static gint
347 sds_download_try (struct backend *backend, const gchar * path,
348 GByteArray * output, struct job_control *control)
349 {
350 guint id, words, word_size, read_bytes, bytes_per_word, total_words, err,
351 retries, packets, packet, exp_packet, rx_packets;
352 gint16 sample;
353 GByteArray *tx_msg, *rx_msg;
354 gchar *path_copy, *index;
355 guint8 *dataptr;
356 gboolean active, first;
357 gboolean last_packet_ack;
358 struct sample_info *sample_info;
359 struct sysex_transfer transfer;
360 struct sds_data *sds_data = backend->data;
361
362 path_copy = strdup (path);
363 index = basename (path_copy);
364 id = atoi (index);
365 g_free (path_copy);
366
367 debug_print (1, "Sending dump request...\n");
368 packet = 0;
369
370 g_mutex_lock (&backend->mutex);
371 backend_rx_drain (backend);
372 g_mutex_unlock (&backend->mutex);
373
374 rx_msg = sds_download_get_header (backend, id);
375 if (!rx_msg)
376 {
377 err = -EIO;
378 goto end;
379 }
380
381 usleep (sds_data->rest_time);
382
383 sample_info = malloc (sizeof (struct sample_info));
384 if (sds_get_download_info (rx_msg, sample_info, &words, &word_size,
385 &bytes_per_word))
386 {
387 free_msg (rx_msg);
388 g_free (sample_info);
389 err = -EINVAL;
390 goto end;
391 }
392
393 packets =
394 ceil (words / (double) (SDS_DATA_PACKET_PAYLOAD_LEN / bytes_per_word));
395 sds_debug_print_sample_data (sample_info->bitdepth, bytes_per_word,
396 word_size, sample_info->samplerate, words,
397 packets);
398
399 g_mutex_lock (&control->mutex);
400 active = control->active;
401 g_mutex_unlock (&control->mutex);
402 control->parts = 1;
403 control->part = 0;
404 set_job_control_progress (control, 0.0);
405 control->data = sample_info;
406
407 debug_print (1, "Receiving dump data...\n");
408
409 tx_msg = g_byte_array_new ();
410 total_words = 0;
411 retries = 0;
412 last_packet_ack = TRUE;
413 err = 0;
414 exp_packet = 0;
415 first = TRUE;
416 rx_packets = 0;
417 while (active && rx_packets <= packets)
418 {
419 if (retries == SDS_MAX_RETRIES)
420 {
421 debug_print (1, "Too many retries\n");
422 break;
423 }
424
425 g_byte_array_set_size (tx_msg, 0);
426 if (last_packet_ack)
427 {
428 g_byte_array_append (tx_msg, SDS_ACK, sizeof (SDS_ACK));
429 }
430 else
431 {
432 g_byte_array_append (tx_msg, SDS_NAK, sizeof (SDS_NAK));
433 }
434 tx_msg->data[4] = packet % 0x80;
435
436 if (rx_packets == packets)
437 {
438 err = sds_tx (backend, tx_msg);
439 goto end;
440 }
441 else
442 {
443 transfer.raw = tx_msg;
444 transfer.timeout = SDS_NO_SPEC_TIMEOUT;
445 err = backend_tx_and_rx_sysex_transfer (backend, &transfer, FALSE);
446 if (err == -ECANCELED)
447 {
448 break;
449 }
450 rx_msg = transfer.raw;
451 }
452
453 if (!rx_msg)
454 {
455 debug_print (2,
456 "Packet not received. Remaining packets: %d; remaining samples: %d\n",
457 packets - rx_packets, words - total_words);
458 //This is a hack to fix a downloading error with an E-Mu ESI-2000 as it never sends the last packet when there is only 1 sample.
459 if ((rx_packets == packets - 1) && (total_words == words - 1))
460 {
461 debug_print (2,
462 "Skipping last packet as it has only one sample...\n");
463 rx_packets++;
464 err = 0;
465 goto end;
466 }
467 err = (rx_packets == packets - 1) ? -EBADMSG : -EINVAL;
468 sds_download_inc_packet (&first, &packet);
469 break;
470 }
471
472 if (rx_msg->len != SDS_DATA_PACKET_LEN)
473 {
474 debug_print (2, "Invalid length. Stopping...\n");
475 free_msg (rx_msg);
476 err = -EBADMSG;
477 break;
478 }
479
480 guint exp_packet_id = exp_packet % 0x80;
481 if (rx_msg->data[4] != exp_packet_id)
482 {
483 debug_print (2, "Invalid packet number. Stopping...\n");
484 free_msg (rx_msg);
485 err = -EINVAL;
486 break;
487 }
488
489 if (last_packet_ack)
490 {
491 sds_download_inc_packet (&first, &packet);
492 }
493
494 if (sds_checksum (rx_msg->data) !=
495 rx_msg->data[SDS_DATA_PACKET_CKSUM_POS])
496 {
497 debug_print (2, "Invalid cksum. Retrying...\n");
498 free_msg (rx_msg);
499 last_packet_ack = FALSE;
500 usleep (sds_data->rest_time);
501 retries++;
502 continue;
503 }
504
505 exp_packet++;
506 rx_packets++;
507
508 last_packet_ack = TRUE;
509 retries = 0;
510
511 read_bytes = 0;
512 dataptr = &rx_msg->data[5];
513 while (read_bytes < SDS_DATA_PACKET_PAYLOAD_LEN && total_words < words)
514 {
515 sample = sds_get_gint16_value_left_just (dataptr,
516 bytes_per_word,
517 sample_info->bitdepth);
518 g_byte_array_append (output, (guint8 *) & sample, sizeof (sample));
519 dataptr += bytes_per_word;
520 read_bytes += bytes_per_word;
521 total_words++;
522 }
523
524 set_job_control_progress (control, rx_packets / (double) packets);
525
526 g_mutex_lock (&control->mutex);
527 active = control->active;
528 g_mutex_unlock (&control->mutex);
529
530 free_msg (rx_msg);
531
532 usleep (sds_data->rest_time);
533 }
534
535 free_msg (tx_msg);
536
537 end:
538 if (active && !err && rx_packets == packets)
539 {
540 debug_print (1, "%d frames received\n", total_words);
541 set_job_control_progress (control, 1.0);
542 }
543 else
544 {
545 debug_print (1, "Cancelling SDS download...\n");
546 usleep (sds_data->rest_time);
547 sds_tx_handshake (backend, SDS_CANCEL, packet % 0x80);
548 }
549
550 return err;
551 }
552
553 static gint
554 sds_download (struct backend *backend, const gchar * path,
555 GByteArray * output, struct job_control *control)
556 {
557 gint err;
558 for (gint i = 0; i < SDS_MAX_RETRIES; i++)
559 {
560 err = sds_download_try (backend, path, output, control);
561 if (err == -EBADMSG)
562 {
563 //We retry the whole download to fix a downloading error with an E-Mu ESI-2000 as it occasionally doesn't send the last packet.
564 debug_print (2, "Bug detected. Retrying download...\n");
565 g_byte_array_set_size (output, 0);
566 }
567 else
568 {
569 break;
570 }
571 }
572 return err;
573 }
574
575 static gint
576 sds_tx_and_wait_ack (struct backend *backend, GByteArray * tx_msg,
577 guint packet, gint timeout, gint timeout2)
578 {
579 gint err;
580 gint t;
581 guint rx_packet;
582 GByteArray *rx_msg;
583 gboolean waiting = FALSE;
584 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, timeout);
585 if (!rx_msg)
586 {
587 return -ETIMEDOUT; //Nothing was received
588 }
589
590 t = timeout2;
591 while (1)
592 {
593 rx_packet = rx_msg->data[4];
594 rx_msg->data[4] = 0;
595
596 if (!memcmp (rx_msg->data, SDS_WAIT, sizeof (SDS_WAIT)) && !waiting)
597 {
598 debug_print (2, "WAIT received. Waiting for an ACK...\n");
599 t = SDS_NO_SPEC_TIMEOUT;
600 waiting = TRUE;
601 }
602 else if (!memcmp (rx_msg->data, SDS_ACK, sizeof (SDS_ACK)))
603 {
604 err = 0;
605 break;
606 }
607 else if (!memcmp (rx_msg->data, SDS_NAK, sizeof (SDS_NAK)))
608 {
609 err = -EBADMSG;
610 break;
611 }
612 else if (!memcmp (rx_msg->data, SDS_CANCEL, sizeof (SDS_CANCEL)))
613 {
614 err = -ECANCELED;
615 break;
616 }
617 else if (rx_packet != packet)
618 {
619 err = -EINVAL; //Unexpected package number
620 break;
621 }
622 else
623 {
624 err = -EIO; //Message received but unrecognized
625 break;
626 }
627
628 free_msg (rx_msg);
629 rx_msg = sds_rx (backend, t);
630 if (!rx_msg)
631 {
632 return -ENOMSG;
633 }
634 }
635
636 free_msg (rx_msg);
637 return err;
638 }
639
640 static inline GByteArray *
641 sds_get_data_packet_msg (gint packet, guint words, guint * word,
642 gint16 ** frame, guint bits, guint bytes_per_word)
643 {
644 guint8 *data;
645 GByteArray *tx_msg = g_byte_array_sized_new (SDS_DATA_PACKET_LEN);
646 g_byte_array_append (tx_msg, SDS_DATA_PACKET_HEADER,
647 sizeof (SDS_DATA_PACKET_HEADER));
648 g_byte_array_set_size (tx_msg, SDS_DATA_PACKET_LEN);
649 tx_msg->data[4] = packet;
650 memset (&tx_msg->data[sizeof (SDS_DATA_PACKET_HEADER)], 0,
651 SDS_DATA_PACKET_PAYLOAD_LEN);
652 tx_msg->data[SDS_DATA_PACKET_LEN - 1] = 0xf7;
653 data = &tx_msg->data[sizeof (SDS_DATA_PACKET_HEADER)];
654 for (guint i = 0; i < SDS_DATA_PACKET_PAYLOAD_LEN; i += bytes_per_word)
655 {
656 if (*word < words)
657 {
658 sds_set_gint16_value_left_just (data, bytes_per_word, bits,
659 **frame);
660 data += bytes_per_word;
661 (*frame)++;
662 (*word)++;
663 }
664 }
665 tx_msg->data[SDS_DATA_PACKET_CKSUM_POS] = sds_checksum (tx_msg->data);
666 return tx_msg;
667 }
668
669 static inline GByteArray *
670 sds_get_rename_sample_msg (guint id, gchar * name)
671 {
672 GByteArray *tx_msg = g_byte_array_new ();
673 guint name_len = strlen (name);
674 name_len = name_len > 127 ? 127 : name_len;
675 g_byte_array_append (tx_msg, SDS_SAMPLE_NAME_HEADER,
676 sizeof (SDS_SAMPLE_NAME_HEADER));
677 tx_msg->data[5] = id % 0x80;
678 tx_msg->data[6] = id / 0x80;
679 g_byte_array_append (tx_msg, (guint8 *) & name_len, 1);
680 g_byte_array_append (tx_msg, (guint8 *) name, name_len);
681 g_byte_array_append (tx_msg, (guint8 *) "\xf7", 1);
682 return tx_msg;
683 }
684
685 static gint
686 sds_rename (struct backend *backend, const gchar * src, const gchar * dst)
687 {
688 GByteArray *tx_msg, *rx_msg;
689 guint id;
690 gint err;
691 gchar *name, *dstcpy;
692 debug_print (1, "Sending rename request...\n");
693 err = common_slot_get_id_name_from_path (src, &id, NULL);
694 if (err)
695 {
696 return err;
697 }
698
699 g_mutex_lock (&backend->mutex);
700 backend_rx_drain (backend);
701 g_mutex_unlock (&backend->mutex);
702
703 dstcpy = strdup (dst);
704 name = basename (dstcpy);
705 tx_msg = sds_get_rename_sample_msg (id, name);
706 err = -ENOSYS;
707 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT);
708 if (rx_msg)
709 {
710 err = 0;
711 free_msg (rx_msg);
712 }
713
714 g_free (dstcpy);
715 return err;
716 }
717
718 static gint
719 sds_upload (struct backend *backend, const gchar * path, GByteArray * input,
720 struct job_control *control, guint bits)
721 {
722 gchar *name;
723 GByteArray *tx_msg;
724 gint16 *frame, *f;
725 gboolean active, open_loop = FALSE;
726 guint word, words, words_per_packet, id, packet = 0, packets, retries =
727 0, w, bytes_per_word;
728 gint err = 0, word_size;
729 struct sds_data *sds_data = backend->data;
730 struct sample_info *sample_info = control->data;
731
732 control->parts = 1;
733 control->part = 0;
734 set_job_control_progress (control, 0.0);
735
736 if (common_slot_get_id_name_from_path (path, &id, &name))
737 {
738 return -EBADSLT;
739 }
740
741 g_mutex_lock (&backend->mutex);
742 backend_rx_drain (backend);
743 g_mutex_unlock (&backend->mutex);
744
745 g_mutex_lock (&control->mutex);
746 active = control->active;
747 g_mutex_unlock (&control->mutex);
748
749 debug_print (1, "Sending dump header...\n");
750
751 words = input->len >> 1; //bytes to words (frames)
752 word_size = (gint) ceil (bits / 8.0);
753 bytes_per_word = (gint) ceil (bits / 7.0);
754 words_per_packet = SDS_DATA_PACKET_PAYLOAD_LEN / bytes_per_word;
755 packets = ceil (words / (double) words_per_packet);
756
757 tx_msg = sds_get_dump_msg (id, words, sample_info, bits);
758 //The first timeout should be SDS_SPEC_TIMEOUT_HANDSHAKE (2 s) buit it is not enough sometimes.
759 err = sds_tx_and_wait_ack (backend, tx_msg, 0, SDS_NO_SPEC_TIMEOUT,
760 SDS_NO_SPEC_TIMEOUT);
761 if (err == -ENOMSG)
762 {
763 debug_print (2, "No packet received after a WAIT. Continuing...\n");
764 }
765 else if (err == -ETIMEDOUT)
766 {
767 //In case of no response, we can assume an open loop.
768 debug_print (1, "Assuming open loop...\n");
769 open_loop = TRUE;
770 }
771 else if (err)
772 {
773 goto cleanup;
774 }
775
776 debug_print (1, "Sending dump data...\n");
777
778 word = 0;
779 sds_debug_print_sample_data (bits, bytes_per_word,
780 word_size, sample_info->samplerate, words,
781 packets);
782 frame = (gint16 *) input->data;
783 while (packet < packets && active)
784 {
785 if (retries == SDS_MAX_RETRIES)
786 {
787 debug_print (1, "Too many retries\n");
788 break;
789 }
790
791 f = frame;
792 w = word;
793 tx_msg = sds_get_data_packet_msg (packet % 0x80, words, &w, &f, bits,
794 bytes_per_word);
795 if (open_loop)
796 {
797 err = sds_tx (backend, tx_msg);
798 usleep (SDS_NO_SPEC_OPEN_LOOP_REST_TIME);
799 }
800 else
801 {
802 //SDS_SPEC_TIMEOUT is too low to be used here.
803 err = sds_tx_and_wait_ack (backend, tx_msg, packet % 0x80,
804 SDS_NO_SPEC_TIMEOUT,
805 SDS_NO_SPEC_TIMEOUT);
806 }
807
808 if (err == -EBADMSG)
809 {
810 debug_print (2, "NAK received. Retrying...\n");
811 retries++;
812 continue;
813 }
814 else if (err == -ENOMSG)
815 {
816 debug_print (2, "No packet received after a WAIT. Continuing...\n");
817 g_mutex_lock (&backend->mutex);
818 backend_rx_drain (backend);
819 g_mutex_unlock (&backend->mutex);
820 }
821 else if (err == -EINVAL)
822 {
823 debug_print (2, "Unexpectd packet number. Continuing...\n");
824 goto end;
825 }
826 else if (err == -ETIMEDOUT)
827 {
828 debug_print (2, "No response. Continuing in open loop...\n");
829 open_loop = TRUE;
830 err = 0;
831 }
832 else if (err == -ECANCELED)
833 {
834 debug_print (2, "Cancelled by device. Stopping...\n");
835 goto end;
836 }
837 else if (err)
838 {
839 error_print ("Unhandled error\n");
840 goto end;
841 }
842
843 set_job_control_progress (control, packet / (gdouble) packets);
844 g_mutex_lock (&control->mutex);
845 active = control->active;
846 g_mutex_unlock (&control->mutex);
847
848 word = w;
849 frame = f;
850 packet++;
851 retries = 0;
852 err = 0;
853
854 usleep (sds_data->rest_time);
855 }
856
857 if (active && sds_data->name_extension)
858 {
859 sds_rename (backend, path, name);
860 }
861
862 end:
863 if (active && packet == packets)
864 {
865 set_job_control_progress (control, 1.0);
866 }
867 else
868 {
869 debug_print (2, "Cancelling SDS upload...\n");
870 sds_tx_handshake (backend, SDS_CANCEL, packet % 0x80);
871 err = -ECANCELED;
872 }
873
874 cleanup:
875 g_free (name);
876 return err;
877 }
878
879 static gint
880 sds_upload_8b (struct backend *backend, const gchar * path,
881 GByteArray * input, struct job_control *control)
882 {
883 return sds_upload (backend, path, input, control, 8);
884 }
885
886 static gint
887 sds_upload_12b (struct backend *backend, const gchar * path,
888 GByteArray * input, struct job_control *control)
889 {
890 return sds_upload (backend, path, input, control, 12);
891 }
892
893 static gint
894 sds_upload_14b (struct backend *backend, const gchar * path,
895 GByteArray * input, struct job_control *control)
896 {
897 return sds_upload (backend, path, input, control, 14);
898 }
899
900 static gint
901 sds_upload_16b (struct backend *backend, const gchar * path,
902 GByteArray * input, struct job_control *control)
903 {
904 return sds_upload (backend, path, input, control, 16);
905 }
906
907 static void
908 sds_free_iterator_data (void *iter_data)
909 {
910 debug_print (2, "No packet received after a WAIT. Continuing...\n");
911 g_free (iter_data);
912 }
913
914 static guint
915 sds_next_dentry (struct item_iterator *iter)
916 {
917 gint next = *((gint *) iter->data);
918 if (next < SDS_SAMPLE_LIMIT)
919 {
920 iter->item.id = next;
921 snprintf (iter->item.name, LABEL_MAX, "%03d", next);
922 iter->item.type = ELEKTROID_FILE;
923 iter->item.size = -1;
924 (*((gint *) iter->data))++;
925 return 0;
926 }
927 else
928 {
929 return -ENOENT;
930 }
931 }
932
933 static gint
934 sds_read_dir (struct backend *backend, struct item_iterator *iter,
935 const gchar * path)
936 {
937 if (strcmp (path, "/"))
938 {
939 return -ENOTDIR;
940 }
941
942 iter->data = g_malloc (sizeof (guint));
943 *((gint *) iter->data) = 0;
944 iter->next = sds_next_dentry;
945 iter->free = sds_free_iterator_data;
946 return 0;
947 }
948
949 gint
950 sds_sample_load (const gchar * path, GByteArray * sample,
951 struct job_control *control)
952 {
953 guint frames;
954 struct sample_params sample_params;
955 sample_params.samplerate = 0; // Any sample rate is valid.
956 sample_params.channels = SDS_SAMPLE_CHANNELS;
957 return sample_load_from_file (path, sample, control, &sample_params,
958 &frames);
959 }
960
961 static void
962 sds_print (struct item_iterator *iter, struct backend *backend)
963 {
964 printf ("%c %s\n", iter->item.type, iter->item.name);
965 }
966
967 enum sds_fs
968 {
969 FS_SAMPLES_SDS_16_B = 0x1,
970 FS_SAMPLES_SDS_14_B = 0x2,
971 FS_SAMPLES_SDS_12_B = 0x4,
972 FS_SAMPLES_SDS_8_B = 0x8
973 };
974
975 static const struct fs_operations FS_SAMPLES_SDS_8B_OPERATIONS = {
976 .fs = FS_SAMPLES_SDS_8_B,
977 .options = FS_OPTION_AUDIO_PLAYER | FS_OPTION_SINGLE_OP |
978 FS_OPTION_ID_AS_FILENAME | FS_OPTION_SLOT_STORAGE | FS_OPTION_SORT_BY_ID,
979 .name = "mono8",
980 .gui_name = "Mono 8 bits",
981 .gui_icon = BE_FILE_ICON_WAVE,
982 .type_ext = "wav",
983 .max_name_len = SDS_SAMPLE_NAME_MAX_LEN,
984 .readdir = sds_read_dir,
985 .print_item = sds_print,
986 .rename = sds_rename,
987 .download = sds_download,
988 .upload = sds_upload_8b,
989 .load = sds_sample_load,
990 .save = sample_save_from_array,
991 .get_ext = backend_get_fs_ext,
992 .get_upload_path = common_slot_get_upload_path,
993 .get_download_path = sds_get_download_path
994 };
995
996 static const struct fs_operations FS_SAMPLES_SDS_12B_OPERATIONS = {
997 .fs = FS_SAMPLES_SDS_12_B,
998 .options = FS_OPTION_AUDIO_PLAYER | FS_OPTION_SINGLE_OP |
999 FS_OPTION_ID_AS_FILENAME | FS_OPTION_SLOT_STORAGE | FS_OPTION_SORT_BY_ID,
1000 .name = "mono12",
1001 .gui_name = "Mono 12 bits",
1002 .gui_icon = BE_FILE_ICON_WAVE,
1003 .type_ext = "wav",
1004 .max_name_len = SDS_SAMPLE_NAME_MAX_LEN,
1005 .readdir = sds_read_dir,
1006 .print_item = sds_print,
1007 .rename = sds_rename,
1008 .download = sds_download,
1009 .upload = sds_upload_12b,
1010 .load = sds_sample_load,
1011 .save = sample_save_from_array,
1012 .get_ext = backend_get_fs_ext,
1013 .get_upload_path = common_slot_get_upload_path,
1014 .get_download_path = sds_get_download_path
1015 };
1016
1017 static const struct fs_operations FS_SAMPLES_SDS_14B_OPERATIONS = {
1018 .fs = FS_SAMPLES_SDS_14_B,
1019 .options = FS_OPTION_AUDIO_PLAYER | FS_OPTION_SINGLE_OP |
1020 FS_OPTION_ID_AS_FILENAME | FS_OPTION_SLOT_STORAGE | FS_OPTION_SORT_BY_ID,
1021 .name = "mono14",
1022 .gui_name = "Mono 14 bits",
1023 .gui_icon = BE_FILE_ICON_WAVE,
1024 .type_ext = "wav",
1025 .max_name_len = SDS_SAMPLE_NAME_MAX_LEN,
1026 .readdir = sds_read_dir,
1027 .print_item = sds_print,
1028 .rename = sds_rename,
1029 .download = sds_download,
1030 .upload = sds_upload_14b,
1031 .load = sds_sample_load,
1032 .save = sample_save_from_array,
1033 .get_ext = backend_get_fs_ext,
1034 .get_upload_path = common_slot_get_upload_path,
1035 .get_download_path = sds_get_download_path
1036 };
1037
1038 static const struct fs_operations FS_SAMPLES_SDS_16B_OPERATIONS = {
1039 .fs = FS_SAMPLES_SDS_16_B,
1040 .options = FS_OPTION_AUDIO_PLAYER | FS_OPTION_SINGLE_OP |
1041 FS_OPTION_ID_AS_FILENAME | FS_OPTION_SLOT_STORAGE | FS_OPTION_SORT_BY_ID,
1042 .name = "mono16",
1043 .gui_name = "Mono 16 bits",
1044 .gui_icon = BE_FILE_ICON_WAVE,
1045 .type_ext = "wav",
1046 .max_name_len = SDS_SAMPLE_NAME_MAX_LEN,
1047 .readdir = sds_read_dir,
1048 .print_item = sds_print,
1049 .rename = sds_rename,
1050 .download = sds_download,
1051 .upload = sds_upload_16b,
1052 .load = sds_sample_load,
1053 .save = sample_save_from_array,
1054 .get_ext = backend_get_fs_ext,
1055 .get_upload_path = common_slot_get_upload_path,
1056 .get_download_path = sds_get_download_path
1057 };
1058
1059 static const struct fs_operations *FS_SDS_ALL_OPERATIONS[] = {
1060 &FS_SAMPLES_SDS_8B_OPERATIONS, &FS_SAMPLES_SDS_12B_OPERATIONS,
1061 &FS_SAMPLES_SDS_14B_OPERATIONS, &FS_SAMPLES_SDS_16B_OPERATIONS, NULL
1062 };
1063
1064 gint
1065 sds_handshake (struct backend *backend)
1066 {
1067 gint err;
1068 GByteArray *tx_msg, *rx_msg;
1069 struct sds_data *sds_data = g_malloc (sizeof (struct sds_data));
1070
1071 //Elektron devices support SDS so we need to be sure it is not.
1072 rx_msg = elektron_ping (backend);
1073 if (rx_msg)
1074 {
1075 free_msg (rx_msg);
1076 g_free (backend->data); //This is filled up by elektron_ping.
1077 return -ENODEV;
1078 }
1079
1080 g_mutex_lock (&backend->mutex);
1081 backend_rx_drain (backend);
1082 g_mutex_unlock (&backend->mutex);
1083
1084 //We send a dump header for a number higher than every device might allow. Hopefully, this will fail on every device.
1085 //Numbers higher than 1500 make an E-Mu ESI-2000 crash when entering into the 'MIDI SAMPLE DUMP' menu but the actual limit is unknown.
1086 tx_msg = sds_get_dump_msg (1000, 0, NULL, 16);
1087 //In case we receive an ACK, NAK or CANCEL, there is a MIDI SDS device listening.
1088 err = sds_tx_and_wait_ack (backend, tx_msg, 0, SDS_SPEC_TIMEOUT_HANDSHAKE,
1089 SDS_NO_SPEC_TIMEOUT_TRY);
1090
1091 if (err && err != -EBADMSG && err != -ECANCELED)
1092 {
1093 return -ENODEV;
1094 }
1095
1096 //We cancel the upload.
1097 usleep (SDS_REST_TIME_DEFAULT);
1098 sds_tx_handshake (backend, SDS_CANCEL, 0);
1099 usleep (SDS_REST_TIME_DEFAULT);
1100
1101 tx_msg = g_byte_array_new ();
1102 g_byte_array_append (tx_msg, SDS_SAMPLE_NAME_REQUEST,
1103 sizeof (SDS_SAMPLE_NAME_REQUEST));
1104 tx_msg->data[5] = 1;
1105 tx_msg->data[6] = 0;
1106 rx_msg = backend_tx_and_rx_sysex (backend, tx_msg, SDS_NO_SPEC_TIMEOUT_TRY);
1107 if (rx_msg)
1108 {
1109 sds_data->name_extension = TRUE;
1110 free_msg (rx_msg);
1111 }
1112 else
1113 {
1114 sds_data->name_extension = FALSE;
1115 }
1116 debug_print (1, "Name extension: %s\n",
1117 sds_data->name_extension ? "yes" : "no");
1118
1119 //The remaining code is meant to set up different devices. These are the default values.
1120
1121 sds_data->rest_time = SDS_REST_TIME_DEFAULT;
1122
1123 backend->device_desc.filesystems =
1124 FS_SAMPLES_SDS_8_B | FS_SAMPLES_SDS_12_B | FS_SAMPLES_SDS_14_B |
1125 FS_SAMPLES_SDS_16_B;
1126 backend->fs_ops = FS_SDS_ALL_OPERATIONS;
1127 backend->destroy_data = backend_destroy_data;
1128 backend->data = sds_data;
1129
1130 if (strlen (backend->device_name))
1131 {
1132 gchar *device_name = strdup (backend->device_name);
1133 snprintf (backend->device_name, LABEL_MAX, "%s %s", _("SDS sampler"),
1134 device_name);
1135 g_free (device_name);
1136 }
1137 else
1138 {
1139 snprintf (backend->device_name, LABEL_MAX, "%s", _("SDS sampler"));
1140 }
1141
1142 return 0;
1143 }
0 /*
1 * sds.h
2 * Copyright (C) 2022 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef SDS_H
21 #define SDS_H
22
23 #include "backend.h"
24
25 gint sds_handshake (struct backend *);
26
27 #endif
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #include "../config.h"
2120 #include <stdio.h>
2221 #include <stdlib.h>
2322 #include <unistd.h>
2625 #include <stdint.h>
2726 #include <inttypes.h>
2827 #include <stddef.h>
28 #include "backend.h"
2929 #include "connector.h"
3030 #include "utils.h"
3131
3232 #define GET_FS_OPS_OFFSET(member) offsetof(struct fs_operations, member)
33 #define GET_FS_OPS_FUNC(type,fs,offset) (*(((type *) (((gchar *) connector_get_fs_operations(fs)) + offset))))
33 #define GET_FS_OPS_FUNC(type,fs,offset) (*(((type *) (((gchar *) fs) + offset))))
3434 #define CHECK_FS_OPS_FUNC(f) if (!(f)) {error_print ("Operation not implemented\n"); return EXIT_FAILURE;}
3535
36 static struct connector connector;
36 static struct backend backend;
3737 static struct job_control control;
38 static const char *devices_filename;
39
40 typedef void (*print_item) (struct item_iterator *);
41
42 static const gchar *CLI_FSS[] = {
43 "sample", "raw", "preset", "data", "project", "sound"
44 };
45
46 static void
47 print_smplrw (struct item_iterator *iter)
48 {
49 gchar *hsize = get_human_size (iter->item.size, FALSE);
50 struct connector_iterator_data *data = iter->data;
51
52 printf ("%c %10s %08x %s\n", iter->item.type,
53 hsize, data->hash, iter->item.name);
54 g_free (hsize);
55 }
56
57 static void
58 print_data (struct item_iterator *iter)
59 {
60 gchar *hsize = get_human_size (iter->item.size, FALSE);
61 struct connector_iterator_data *data = iter->data;
62
63 printf ("%c %3d %04x %d %d %10s %s\n", iter->item.type,
64 iter->item.index, data->operations, data->has_valid_data,
65 data->has_metadata, hsize, iter->item.name);
66 g_free (hsize);
67 }
68
69 static void
70 null_control_callback (gdouble foo)
71 {
72 }
38 static gchar *connector, *fs, *op;
39 const struct fs_operations *fs_ops;
7340
7441 static const gchar *
7542 cli_get_path (gchar * device_path)
7643 {
7744 gint len = strlen (device_path);
78 char *path = device_path;
45 gchar *path = device_path;
7946 gint i = 0;
8047
8148 while (path[0] != '/' && i < len)
9158 cli_ld ()
9259 {
9360 gint i;
94 struct connector_system_device device;
95 GArray *devices = connector_get_system_devices ();
61 struct backend_system_device device;
62 GArray *devices = backend_get_system_devices ();
9663
9764 for (i = 0; i < devices->len; i++)
9865 {
99 device = g_array_index (devices, struct connector_system_device, i);
100 printf ("%d %s\n", device.card, device.name);
66 device = g_array_index (devices, struct backend_system_device, i);
67 printf ("%d: %s %s\n", i, device.id, device.name);
10168 }
10269
10370 g_array_free (devices, TRUE);
10673 }
10774
10875 static gint
109 cli_connect (const char *device_path, enum connector_fs fs)
110 {
111 gint card = atoi (device_path);
112 gint ret = connector_init (&connector, card, devices_filename);
113 if (!ret && fs && !(connector.device_desc.filesystems & fs))
114 {
115 error_print ("Filesystem not supported for device '%s'\n",
116 connector.device_desc.name);
117 return 1;
118 }
119 return ret;
120 }
121
122 static int
123 cli_list (int argc, char *argv[], int optind, enum connector_fs fs,
124 print_item print)
76 cli_connect (const gchar * device_path)
77 {
78 gint err, id = (gint) atoi (device_path);
79 struct backend_system_device device;
80 GArray *devices = backend_get_system_devices ();
81
82 if (!devices->len)
83 {
84 error_print ("Invalid device %d\n", id);
85 return -ENODEV;
86 }
87
88 device = g_array_index (devices, struct backend_system_device, id);
89 err = connector_init (&backend, device.id, connector, NULL);
90 g_array_free (devices, TRUE);
91
92 if (!err && fs)
93 {
94 fs_ops = backend_get_fs_operations (&backend, 0, fs);
95 if (!fs_ops)
96 {
97 error_print ("Invalid filesystem '%s'\n", fs);
98 return -EINVAL;
99 }
100 }
101
102 return err;
103 }
104
105 static int
106 cli_list (int argc, gchar * argv[], int *optind)
125107 {
126108 const gchar *path;
127109 struct item_iterator iter;
128110 gchar *device_path;
129 const struct fs_operations *fs_ops = connector_get_fs_operations (fs);
130
131 if (optind == argc)
111
112 if (*optind == argc)
132113 {
133114 error_print ("Remote path missing\n");
134115 return EXIT_FAILURE;
135116 }
136117 else
137118 {
138 device_path = argv[optind];
139 }
140
141 if (cli_connect (device_path, fs))
119 device_path = argv[*optind];
120 (*optind)++;
121 }
122
123 if (cli_connect (device_path))
142124 {
143125 return EXIT_FAILURE;
144126 }
145127
146128 path = cli_get_path (device_path);
147129
148 if (fs_ops->readdir (&iter, path, &connector))
130 CHECK_FS_OPS_FUNC (fs_ops->readdir);
131 if (fs_ops->readdir (&backend, &iter, path))
149132 {
150133 return EXIT_FAILURE;
151134 }
152135
153136 while (!next_item_iterator (&iter))
154137 {
155 print (&iter);
138 fs_ops->print_item (&iter, &backend);
156139 }
157140
158141 free_item_iterator (&iter);
161144 }
162145
163146 static int
164 cli_command_path (int argc, char *argv[], int optind, enum connector_fs fs,
147 cli_command_path (int argc, gchar * argv[], int *optind,
165148 ssize_t member_offset)
166149 {
167150 const gchar *path;
169152 gint ret;
170153 fs_path_func f;
171154
172 if (optind == argc)
155 if (*optind == argc)
173156 {
174157 error_print ("Remote path missing\n");
175158 return EXIT_FAILURE;
176159 }
177160 else
178161 {
179 device_path = argv[optind];
180 }
181
182 if (cli_connect (device_path, fs))
162 device_path = argv[*optind];
163 (*optind)++;
164 }
165
166 if (cli_connect (device_path))
183167 {
184168 return EXIT_FAILURE;
185169 }
186170
187171 path = cli_get_path (device_path);
188172
189 f = GET_FS_OPS_FUNC (fs_path_func, fs, member_offset);
173 f = GET_FS_OPS_FUNC (fs_path_func, fs_ops, member_offset);
190174 CHECK_FS_OPS_FUNC (f);
191 ret = f (path, &connector);
175 ret = f (&backend, path);
192176 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
193177 }
194178
195179 static int
196 cli_command_src_dst (int argc, char *argv[], int optind, enum connector_fs fs,
180 cli_command_src_dst (int argc, gchar * argv[], int *optind,
197181 ssize_t member_offset)
198182 {
199183 const gchar *src_path, *dst_path;
203187 int ret;
204188 fs_src_dst_func f;
205189
206 if (optind == argc)
190 if (*optind == argc)
207191 {
208192 error_print ("Remote path source missing\n");
209193 return EXIT_FAILURE;
210194 }
211195 else
212196 {
213 device_src_path = argv[optind];
214 optind++;
215 }
216
217 if (optind == argc)
197 device_src_path = argv[*optind];
198 (*optind)++;
199 }
200
201 if (*optind == argc)
218202 {
219203 error_print ("Remote path destination missing\n");
220204 return EXIT_FAILURE;
221205 }
222206 else
223207 {
224 device_dst_path = argv[optind];
208 device_dst_path = argv[*optind];
209 (*optind)++;
225210 }
226211
227212 src_card = atoi (device_src_path);
232217 return EXIT_FAILURE;
233218 }
234219
235 if (cli_connect (device_src_path, 0))
236 {
237 return EXIT_FAILURE;
238 }
239
240 f = GET_FS_OPS_FUNC (fs_src_dst_func, fs, member_offset);
220 if (cli_connect (device_src_path))
221 {
222 return EXIT_FAILURE;
223 }
224
225 f = GET_FS_OPS_FUNC (fs_src_dst_func, fs_ops, member_offset);
241226 CHECK_FS_OPS_FUNC (f);
242227 src_path = cli_get_path (device_src_path);
243228 dst_path = cli_get_path (device_dst_path);
244 ret = f (src_path, dst_path, &connector);
229 ret = f (&backend, src_path, dst_path);
245230 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
246231 }
247232
248233 static int
249 cli_info (int argc, char *argv[], int optind)
234 cli_command_mv_rename (int argc, gchar * argv[], int *optind)
235 {
236 const gchar *src_path, *dst_path;
237 gchar *device_src_path, *device_dst_path;
238 gint src_card;
239 gint dst_card;
240 int ret;
241 fs_src_dst_func f;
242
243 if (*optind == argc)
244 {
245 error_print ("Remote path source missing\n");
246 return EXIT_FAILURE;
247 }
248 else
249 {
250 device_src_path = argv[*optind];
251 (*optind)++;
252 }
253
254 if (*optind == argc)
255 {
256 error_print ("Remote path destination missing\n");
257 return EXIT_FAILURE;
258 }
259 else
260 {
261 device_dst_path = argv[*optind];
262 (*optind)++;
263 }
264
265 if (cli_connect (device_src_path))
266 {
267 return EXIT_FAILURE;
268 }
269
270 src_card = atoi (device_src_path);
271 src_path = cli_get_path (device_src_path);
272
273 // If move is implemented, rename must behave the same way.
274 f = fs_ops->move;
275 if (f)
276 {
277 dst_card = atoi (device_dst_path);
278 if (src_card != dst_card)
279 {
280 error_print ("Source and destination device must be the same\n");
281 return EXIT_FAILURE;
282 }
283 dst_path = cli_get_path (device_dst_path);
284 }
285 else
286 {
287 f = fs_ops->rename;
288 dst_path = device_dst_path;
289 }
290
291 CHECK_FS_OPS_FUNC (f);
292 ret = f (&backend, src_path, dst_path);
293 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
294 }
295
296 static int
297 cli_info (int argc, gchar * argv[], int *optind)
250298 {
251299 gchar *device_path;
252 gchar *comma;
253
254 if (optind == argc)
300 const gchar *name;
301
302 if (*optind == argc)
255303 {
256304 error_print ("Device missing\n");
257305 return EXIT_FAILURE;
258306 }
259307 else
260308 {
261 device_path = argv[optind];
262 }
263
264 if (cli_connect (device_path, 0))
265 {
266 return EXIT_FAILURE;
267 }
268
269 printf ("%s filesystems=", connector.device_name);
270 comma = "";
271 for (int fs = FS_SAMPLES, i = 0; fs <= FS_DATA_SND; fs <<= 1, i++)
272 {
273 if (connector.device_desc.filesystems & fs)
274 {
275 printf ("%s%s", comma, CLI_FSS[i]);
276 }
277 comma = ",";
309 device_path = argv[*optind];
310 (*optind)++;
311 }
312
313 if (cli_connect (device_path))
314 {
315 return EXIT_FAILURE;
316 }
317
318 printf ("%s; filesystems=", backend.device_name);
319
320 for (gint fs = 1; fs <= MAX_BACKEND_FSS; fs <<= 1)
321 {
322 if (backend.device_desc.filesystems & fs)
323 {
324 name = backend_get_fs_operations (&backend, fs, NULL)->name;
325 printf ("%s%s", fs == 1 ? "" : ",", name);
326 }
278327 }
279328 printf ("\n");
280329
282331 }
283332
284333 static int
285 cli_df (int argc, char *argv[], int optind)
334 cli_df (int argc, gchar * argv[], int *optind)
286335 {
287336 gchar *device_path;
288337 gchar *size;
289338 gchar *diff;
290339 gchar *free;
291 gint res;
292 struct connector_storage_stats statfs;
293 enum connector_storage storage;
294
295 if (optind == argc)
340 gint res, storage;
341 struct backend_storage_stats statfs;
342
343 if (*optind == argc)
296344 {
297345 error_print ("Device missing\n");
298346 return EXIT_FAILURE;
299347 }
300348 else
301349 {
302 device_path = argv[optind];
303 }
304
305 if (cli_connect (device_path, 0))
306 {
307 return EXIT_FAILURE;
308 }
309
310 if (!connector.device_desc.storage)
350 device_path = argv[*optind];
351 (*optind)++;
352 }
353
354 if (cli_connect (device_path))
355 {
356 return EXIT_FAILURE;
357 }
358
359 if (!backend.device_desc.storage || !backend.get_storage_stats)
311360 {
312361 return EXIT_FAILURE;
313362 }
316365 "Used", "Available", "Use%");
317366
318367 res = 0;
319 for (storage = STORAGE_PLUS_DRIVE; storage <= STORAGE_RAM; storage <<= 1)
320 {
321 if (connector.device_desc.storage & storage)
322 {
323 res |= connector_get_storage_stats (&connector, storage, &statfs);
368 for (storage = 1; storage < MAX_BACKEND_STORAGE; storage <<= 1)
369 {
370 if (backend.device_desc.storage & storage)
371 {
372 res |= backend.get_storage_stats (&backend, storage, &statfs);
324373 if (res)
325374 {
326375 continue;
330379 free = get_human_size (statfs.bfree, FALSE);
331380 printf ("%-10.10s%16s%16s%16s%10.2f%%\n",
332381 statfs.name, size, diff, free,
333 connector_get_storage_stats_percent (&statfs));
382 backend_get_storage_stats_percent (&statfs));
334383 g_free (size);
335384 g_free (diff);
336385 g_free (free);
341390 }
342391
343392 static int
344 cli_upgrade (int argc, char *argv[], int optind)
393 cli_upgrade_os (int argc, gchar * argv[], int *optind)
345394 {
346395 gint res;
347396 const gchar *src_path;
348397 const gchar *device_path;
349 struct connector_sysex_transfer sysex_transfer;
350
351 if (optind == argc)
398 struct sysex_transfer sysex_transfer;
399
400 if (*optind == argc)
352401 {
353402 error_print ("Local path missing\n");
354403 return EXIT_FAILURE;
355404 }
356405 else
357406 {
358 src_path = argv[optind];
359 optind++;
360 }
361
362 if (optind == argc)
407 src_path = argv[*optind];
408 (*optind)++;
409 }
410
411 if (*optind == argc)
363412 {
364413 error_print ("Remote path missing\n");
365414 return EXIT_FAILURE;
366415 }
367416 else
368417 {
369 device_path = argv[optind];
370 }
371
372 if (cli_connect (device_path, 0))
418 device_path = argv[*optind];
419 (*optind)++;
420 }
421
422 if (cli_connect (device_path))
373423 {
374424 return EXIT_FAILURE;
375425 }
383433 else
384434 {
385435 sysex_transfer.active = TRUE;
386 sysex_transfer.timeout = SYSEX_TIMEOUT;
387 res = connector_upgrade_os (&connector, &sysex_transfer);
436 sysex_transfer.timeout = BE_SYSEX_TIMEOUT_MS;
437 CHECK_FS_OPS_FUNC (backend.upgrade_os);
438 res = backend.upgrade_os (&backend, &sysex_transfer);
388439 }
389440
390441 g_byte_array_free (sysex_transfer.raw, TRUE);
392443 }
393444
394445 static int
395 cli_download (int argc, char *argv[], int optind, enum connector_fs fs)
396 {
397 const gchar *src_path;
446 cli_download (int argc, gchar * argv[], int *optind)
447 {
448 const gchar *src_path, *src_dir;
449 gchar *src_dirc;
450 struct item_iterator iter;
398451 gchar *device_src_path, *download_path;
399452 gint res;
400453 GByteArray *array;
401 const struct fs_operations *fs_ops;
402
403 if (optind == argc)
454
455 if (*optind == argc)
404456 {
405457 error_print ("Remote path missing\n");
406458 return EXIT_FAILURE;
407459 }
408460 else
409461 {
410 device_src_path = argv[optind];
411 }
412
413 if (cli_connect (device_src_path, fs))
414 {
415 return EXIT_FAILURE;
416 }
417
418 fs_ops = connector_get_fs_operations (fs);
462 device_src_path = argv[*optind];
463 (*optind)++;
464 }
465
466 if (cli_connect (device_src_path))
467 {
468 return EXIT_FAILURE;
469 }
470
419471 src_path = cli_get_path (device_src_path);
420472
421473 control.active = TRUE;
422 control.callback = null_control_callback;
423474 array = g_byte_array_new ();
424 res = fs_ops->download (src_path, array, &control, &connector);
475 res = fs_ops->download (&backend, src_path, array, &control);
425476 if (res)
426477 {
427478 goto end;
428479 }
429480
430 download_path = connector_get_download_path (&connector, NULL, fs_ops, ".",
431 src_path);
481 src_dirc = strdup (src_path);
482 src_dir = dirname (src_dirc);
483 res = fs_ops->readdir (&backend, &iter, src_dir);
484 g_free (src_dirc);
485 if (res)
486 {
487 goto end;
488 }
489
490 download_path = fs_ops->get_download_path (&backend, &iter, fs_ops, ".",
491 src_path);
432492 if (!download_path)
433493 {
434494 res = -1;
445505 }
446506
447507 static int
448 cli_upload (int argc, char *argv[], int optind, enum connector_fs fs)
508 cli_upload (int argc, gchar * argv[], int *optind)
449509 {
450510 const gchar *dst_dir;
451511 gchar *src_path, *device_dst_path, *upload_path;
452512 gint res;
453513 GByteArray *array;
454514 gint32 index = 1;
455 const struct fs_operations *fs_ops;
456
457 if (optind == argc)
515
516 if (*optind == argc)
458517 {
459518 error_print ("Local path missing\n");
460519 return EXIT_FAILURE;
461520 }
462521 else
463522 {
464 src_path = argv[optind];
465 optind++;
466 }
467
468 if (optind == argc)
523 src_path = argv[*optind];
524 (*optind)++;
525 }
526
527 if (*optind == argc)
469528 {
470529 error_print ("Remote path missing\n");
471530 return EXIT_FAILURE;
472531 }
473532 else
474533 {
475 device_dst_path = argv[optind];
476 }
477
478 if (cli_connect (device_dst_path, fs))
479 {
480 return EXIT_FAILURE;
481 }
482
483 fs_ops = connector_get_fs_operations (fs);
534 device_dst_path = argv[*optind];
535 (*optind)++;
536 }
537
538 if (cli_connect (device_dst_path))
539 {
540 return EXIT_FAILURE;
541 }
542
484543 dst_dir = cli_get_path (device_dst_path);
485544
486 upload_path = connector_get_upload_path (&connector, NULL, fs_ops,
487 dst_dir, src_path, &index);
545 upload_path = fs_ops->get_upload_path (&backend, NULL, fs_ops, dst_dir,
546 src_path, &index);
488547
489548 array = g_byte_array_new ();
490549 control.active = TRUE;
491 control.callback = null_control_callback;
492550 res = fs_ops->load (src_path, array, &control);
493551 if (res)
494552 {
495553 goto cleanup;
496554 }
497555
498 res = fs_ops->upload (upload_path, array, &control, &connector);
556 res = fs_ops->upload (&backend, upload_path, array, &control);
499557 g_free (control.data);
500558
501559 cleanup:
504562 return res ? EXIT_FAILURE : EXIT_SUCCESS;
505563 }
506564
507 static gint
508 get_fs_operations_from_type (const gchar * type)
509 {
510 if (!strlen (type))
511 {
512 return 0;
513 }
514
515 for (gint fs = FS_SAMPLES, i = 0; fs <= FS_DATA_SND; fs <<= 1, i++)
516 {
517 if (strcmp (type, CLI_FSS[i]) == 0)
518 {
519 return fs;
520 }
521 }
522
523 return -1;
524 }
525
526 static gint
527 get_op_type_from_command (const gchar * cmd, char *op, char *type)
528 {
529 gint i;
530 gchar *c;
531 gint len;
532
533 strncpy (op, cmd, LABEL_MAX);
534 op[LABEL_MAX - 1] = 0;
535 len = strlen (op);
536 c = op;
537 for (i = 0; i < LABEL_MAX && i < strlen (op); i++, c++)
538 {
539 if (*c == '-')
540 {
541 *c = 0;
542 break;
543 }
544 }
545 if (i < len - 1)
546 {
547 c++;
548 strncpy (type, c, LABEL_MAX);
549 type[LABEL_MAX - 1] = 0;
550 }
551 else
552 {
553 *type = 0;
554 }
555
556 return get_fs_operations_from_type (type);
565 static int
566 cli_send (int argc, gchar * argv[], int *optind)
567 {
568 gint err;
569 const gchar *device_dst_path, *src_file;
570 struct sysex_transfer sysex_transfer;
571
572 if (*optind == argc)
573 {
574 error_print ("Source file missing\n");
575 return EXIT_FAILURE;
576 }
577 else
578 {
579 src_file = argv[*optind];
580 (*optind)++;
581 }
582
583 if (*optind == argc)
584 {
585 error_print ("Remote device missing\n");
586 return EXIT_FAILURE;
587 }
588 else
589 {
590 device_dst_path = argv[*optind];
591 (*optind)++;
592 }
593
594 connector = "default";
595 if (cli_connect (device_dst_path))
596 {
597 return EXIT_FAILURE;
598 }
599
600 sysex_transfer.active = TRUE;
601 sysex_transfer.timeout = BE_DUMP_TIMEOUT;
602 sysex_transfer.raw = g_byte_array_new ();
603
604 err = load_file (src_file, sysex_transfer.raw, NULL);
605
606 if (!err)
607 {
608 err = backend_tx_sysex (&backend, &sysex_transfer);
609 }
610
611 free_msg (sysex_transfer.raw);
612
613 return err;
614 }
615
616 static int
617 cli_receive (int argc, gchar * argv[], int *optind)
618 {
619 gint err;
620 const gchar *device_src_path, *dst_file;
621 struct sysex_transfer sysex_transfer;
622
623 if (*optind == argc)
624 {
625 error_print ("Remote device missing\n");
626 return EXIT_FAILURE;
627 }
628 else
629 {
630 device_src_path = argv[*optind];
631 (*optind)++;
632 }
633
634 if (*optind == argc)
635 {
636 error_print ("Destination file missing\n");
637 return EXIT_FAILURE;
638 }
639 else
640 {
641 dst_file = argv[*optind];
642 (*optind)++;
643 }
644
645 connector = "default";
646 if (cli_connect (device_src_path))
647 {
648 return EXIT_FAILURE;
649 }
650
651 sysex_transfer.timeout = BE_DUMP_TIMEOUT;
652 sysex_transfer.batch = TRUE;
653
654 backend_rx_drain (&backend);
655 //This doesn't need to be synchronized because the CLI is not multithreaded.
656 err = backend_rx_sysex (&backend, &sysex_transfer);
657 if (!err)
658 {
659 err = save_file (dst_file, sysex_transfer.raw, NULL);
660 }
661
662 free_msg (sysex_transfer.raw);
663
664 return err;
665 }
666
667 gint
668 set_conn_fs_op_from_command (const gchar * cmd)
669 {
670 gchar *aux;
671
672 connector = strdup (cmd);
673 aux = strchr (connector, '-');
674 if (!aux)
675 {
676 g_free (connector);
677 return -1;
678 }
679 *aux = 0;
680 aux++;
681
682 fs = strdup (aux);
683 aux = strchr (fs, '-');
684 if (!aux)
685 {
686 g_free (connector);
687 g_free (fs);
688 return -1;
689 }
690
691 *aux = 0;
692 aux++;
693
694 op = strdup (aux);
695
696 return 0;
557697 }
558698
559699 static void
560700 cli_end (int sig)
561701 {
702 g_mutex_lock (&control.mutex);
562703 control.active = FALSE;
704 g_mutex_unlock (&control.mutex);
563705 }
564706
565707 int
566 main (int argc, char *argv[])
708 main (int argc, gchar * argv[])
567709 {
568710 gint c;
569711 gint res;
570712 gchar *command;
571713 gint vflg = 0, errflg = 0;
572 struct sigaction action, old_action;
573 gint fs;
574 char op[LABEL_MAX];
575 char type[LABEL_MAX];
714 struct sigaction action;
576715
577716 action.sa_handler = cli_end;
578717 sigemptyset (&action.sa_mask);
579718 action.sa_flags = 0;
580
581 sigaction (SIGTERM, NULL, &old_action);
582 if (old_action.sa_handler != SIG_IGN)
583 {
584 sigaction (SIGTERM, &action, NULL);
585 }
586
587 sigaction (SIGQUIT, NULL, &old_action);
588 if (old_action.sa_handler != SIG_IGN)
589 {
590 sigaction (SIGQUIT, &action, NULL);
591 }
592
593 sigaction (SIGINT, NULL, &old_action);
594 if (old_action.sa_handler != SIG_IGN)
595 {
596 sigaction (SIGINT, &action, NULL);
597 }
598
599 sigaction (SIGHUP, NULL, &old_action);
600 if (old_action.sa_handler != SIG_IGN)
601 {
602 sigaction (SIGHUP, &action, NULL);
603 }
604
605 devices_filename = NULL;
606
607 while ((c = getopt (argc, argv, "f:v")) != -1)
719 sigaction (SIGTERM, &action, NULL);
720 sigaction (SIGQUIT, &action, NULL);
721 sigaction (SIGINT, &action, NULL);
722 sigaction (SIGHUP, &action, NULL);
723
724 while ((c = getopt (argc, argv, "v")) != -1)
608725 {
609726 switch (c)
610727 {
611 case 'f':
612 devices_filename = optarg;
613 break;
614728 case 'v':
615729 vflg++;
616730 break;
637751 if (errflg > 0)
638752 {
639753 fprintf (stderr, "%s\n", PACKAGE_STRING);
640 char *exec_name = basename (argv[0]);
754 gchar *exec_name = basename (argv[0]);
641755 fprintf (stderr, "Usage: %s [options] command\n", exec_name);
642756 exit (EXIT_FAILURE);
643757 }
644758
645 fs = get_op_type_from_command (command, op, type);
646 debug_print (1, "Operation: '%s'; filesystem: '%s' (%d)\n", op, type, fs);
647 if (fs < 0)
648 {
649 error_print ("Filesystem '%s' not recognized\n", type);
650 res = EXIT_FAILURE;
651 goto end;
652 }
653
654 if (!fs)
655 {
656 if (strcmp (command, "ld") == 0
657 || strcmp (command, "list-devices") == 0)
658 {
659 res = cli_ld ();
660 }
661 else if (strcmp (op, "info") == 0
662 || strcmp (command, "info-devices") == 0)
663 {
664 res = cli_info (argc, argv, optind);
665 }
666 else if (strcmp (command, "df") == 0
667 || strcmp (command, "info-storage") == 0)
668 {
669 res = cli_df (argc, argv, optind);
670 }
671 else if (strcmp (command, "upgrade") == 0)
672 {
673 res = cli_upgrade (argc, argv, optind);
674 }
675 else if (strcmp (command, "ls") == 0)
676 {
677 res = cli_list (argc, argv, optind, FS_SAMPLES, print_smplrw);
678 }
679 else if (strcmp (command, "mkdir") == 0)
680 {
681 res =
682 cli_command_path (argc, argv, optind, FS_SAMPLES,
683 GET_FS_OPS_OFFSET (mkdir));
684 }
685 else if (strcmp (command, "mv") == 0)
686 {
687 res =
688 cli_command_src_dst (argc, argv, optind, FS_SAMPLES,
689 GET_FS_OPS_OFFSET (move));
690 }
691 else if (strcmp (command, "rm") == 0 || strcmp (command, "rmdir") == 0)
692 {
693 res =
694 cli_command_path (argc, argv, optind, FS_SAMPLES,
695 GET_FS_OPS_OFFSET (delete));
696 }
697 else if (strcmp (command, "download") == 0
698 || strcmp (command, "dl") == 0)
699 {
700 res = cli_download (argc, argv, optind, FS_SAMPLES);
701 }
702 else if (strcmp (command, "upload") == 0 || strcmp (command, "ul") == 0)
703 {
704 res = cli_upload (argc, argv, optind, FS_SAMPLES);
759 if (!strcmp (command, "ld") || !strcmp (command, "list-devices"))
760 {
761 res = cli_ld ();
762 }
763 else if (!strcmp (command, "info") || !strcmp (command, "info-device"))
764 {
765 res = cli_info (argc, argv, &optind);
766 }
767 else if (!strcmp (command, "df") || !strcmp (command, "info-storage"))
768 {
769 res = cli_df (argc, argv, &optind);
770 }
771 else if (!strcmp (command, "send"))
772 {
773 res = cli_send (argc, argv, &optind);
774 }
775 else if (!strcmp (command, "receive"))
776 {
777 res = cli_receive (argc, argv, &optind);
778 }
779 else if (!strcmp (command, "upgrade"))
780 {
781 res = cli_upgrade_os (argc, argv, &optind);
782 }
783 else
784 {
785 if (set_conn_fs_op_from_command (command))
786 {
787 exit (EXIT_FAILURE);
788 }
789
790 debug_print (1,
791 "Connector: \"%s\"; filesystem: \"%s\"; operation: \"%s\"\n",
792 connector, fs, op);
793
794 if (!strcmp (op, "ls") || !strcmp (op, "list"))
795 {
796 res = cli_list (argc, argv, &optind);
797 }
798 else if (!strcmp (op, "mkdir"))
799 {
800 res = cli_command_path (argc, argv, &optind,
801 GET_FS_OPS_OFFSET (mkdir));
802 }
803 else if (!strcmp (op, "rm") || !strcmp (op, "rmdir"))
804 {
805 res = cli_command_path (argc, argv, &optind,
806 GET_FS_OPS_OFFSET (delete));
807 }
808 else if (!strcmp (op, "download") || !strcmp (op, "dl"))
809 {
810 res = cli_download (argc, argv, &optind);
811 }
812 else if (!strcmp (op, "upload") || !strcmp (op, "ul"))
813 {
814 res = cli_upload (argc, argv, &optind);
815 }
816 else if (!strcmp (op, "cl"))
817 {
818 res = cli_command_path (argc, argv, &optind,
819 GET_FS_OPS_OFFSET (clear));
820 }
821 else if (!strcmp (op, "cp"))
822 {
823 res = cli_command_src_dst (argc, argv, &optind,
824 GET_FS_OPS_OFFSET (copy));
825 }
826 else if (!strcmp (op, "sw"))
827 {
828 res = cli_command_src_dst (argc, argv, &optind,
829 GET_FS_OPS_OFFSET (swap));
830 }
831 else if (!strcmp (op, "mv"))
832 {
833 res = cli_command_mv_rename (argc, argv, &optind);
705834 }
706835 else
707836 {
708837 error_print ("Command '%s' not recognized\n", command);
709838 res = EXIT_FAILURE;
710839 }
711 goto end;
712 }
713
714 if (strcmp (op, "ls") == 0 || strcmp (op, "list") == 0)
715 {
716 print_item print = (fs == FS_SAMPLES || fs == FS_RAW_ALL
717 || fs ==
718 FS_RAW_PRESETS) ? print_smplrw : print_data;
719 res = cli_list (argc, argv, optind, fs, print);
720 }
721 else if (strcmp (op, "mkdir") == 0)
722 {
723 res =
724 cli_command_path (argc, argv, optind, fs, GET_FS_OPS_OFFSET (mkdir));
725 }
726 else if (strcmp (op, "rm") == 0 || strcmp (op, "rmdir") == 0)
727 {
728 res =
729 cli_command_path (argc, argv, optind, fs, GET_FS_OPS_OFFSET (delete));
730 }
731 else if (strcmp (op, "download") == 0 || strcmp (op, "dl") == 0)
732 {
733 res = cli_download (argc, argv, optind, fs);
734 }
735 else if (strcmp (op, "upload") == 0 || strcmp (op, "ul") == 0)
736 {
737 res = cli_upload (argc, argv, optind, fs);
738 }
739 else if (strcmp (op, "cl") == 0)
740 {
741 res = cli_command_path (argc, argv, optind, fs,
742 GET_FS_OPS_OFFSET (clear));
743 }
744 else if (strcmp (op, "cp") == 0)
745 {
746 res = cli_command_src_dst (argc, argv, optind, fs,
747 GET_FS_OPS_OFFSET (copy));
748 }
749 else if (strcmp (op, "sw") == 0)
750 {
751 res = cli_command_src_dst (argc, argv, optind, fs,
752 GET_FS_OPS_OFFSET (swap));
753 }
754 else if (strcmp (op, "mv") == 0)
755 {
756 res = cli_command_src_dst (argc, argv, optind, fs,
757 GET_FS_OPS_OFFSET (move));
758 }
759 else
760 {
761 error_print ("Command '%s' not recognized\n", command);
762 res = EXIT_FAILURE;
763 }
764
765 end:
766 if (connector_check (&connector))
767 {
768 connector_destroy (&connector);
769 }
770
771 usleep (REST_TIME * 2);
840
841 if (backend_check (&backend))
842 {
843 backend_destroy (&backend);
844 }
845
846 g_free (connector);
847 g_free (fs);
848 g_free (op);
849 }
850
851
852 usleep (BE_REST_TIME_US * 2);
772853 return res;
773854 }
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #include "../config.h"
2120 #include <limits.h>
2221 #include <locale.h>
2322 #include <gtk/gtk.h>
2524 #include <glib/gi18n.h>
2625 #include <glib/gprintf.h>
2726 #include <getopt.h>
27 #include "backend.h"
2828 #include "connector.h"
2929 #include "browser.h"
3030 #include "audio.h"
3131 #include "sample.h"
3232 #include "utils.h"
33 #include "notifier.h"
3433 #include "local.h"
3534 #include "preferences.h"
3635
36 #define PLAYER_VISIBLE (remote_browser.fs_ops->options & FS_OPTION_AUDIO_PLAYER ? TRUE : FALSE)
37 #define PLAYER_PREF_CHANNELS (!remote_browser.fs_ops || (remote_browser.fs_ops->options & FS_OPTION_STEREO) || !preferences.mix ? 2 : 1)
38 #define PLAYER_LOADED_CHANNELS (PLAYER_PREF_CHANNELS == 2 && sample_info->channels == 2 ? 2 : 1)
39 #define PLAYER_GET_SOURCE(browser) (browser == &local_browser ? AUDIO_SRC_LOCAL : AUDIO_SRC_REMOTE)
40 #define PLAYER_SOURCE_IS_BROWSER(browser) (PLAYER_GET_SOURCE(browser) == audio.src)
41
3742 #define MAX_DRAW_X 10000
3843
39 #define DUMP_TIMEOUT 2000
4044 #define DND_TIMEOUT 1000
4145
4246 #define TEXT_URI_LIST_STD "text/uri-list"
4347 #define TEXT_URI_LIST_ELEKTROID "text/uri-list-elektroid"
4448
45 #define GUI_FSS (FS_SAMPLES | FS_RAW_PRESETS | FS_DATA_PRJ | FS_DATA_SND)
46
4749 #define MSG_WARN_SAME_SRC_DST "Same source and destination path. Skipping...\n"
4850
4951 enum device_list_store_columns
5052 {
51 DEVICES_LIST_STORE_CARD_FIELD,
53 DEVICES_LIST_STORE_ID_FIELD,
5254 DEVICES_LIST_STORE_NAME_FIELD
5355 };
5456
101103 const struct fs_operations *fs_ops; //Contains the fs_operations to use in this transfer
102104 };
103105
104 struct elektroid_add_upload_task_data
105 {
106 struct item_iterator iter;
107 gint32 index;
108 };
109
110 typedef int (*connector_send_raw) (struct connector *,
111 struct connector_sysex_transfer *);
112
113106 static gpointer elektroid_upload_task (gpointer);
114107 static gpointer elektroid_download_task (gpointer);
115 static void elektroid_update_progress (gdouble);
108 static void elektroid_update_progress (struct job_control *);
109 static void elektroid_cancel_all_tasks (GtkWidget *, gpointer);
110 static void elektroid_reset_sample (struct browser *);
116111
117112 static const struct option ELEKTROID_OPTIONS[] = {
118113 {"local-directory", 1, NULL, 'l'},
121116 {NULL, 0, NULL, 0}
122117 };
123118
124 static const gchar *ELEKTROID_FS_ICONS[] = {
125 FILE_ICON_WAVE, FILE_ICON_DATA, FILE_ICON_SND, FILE_ICON_DATA,
126 FILE_ICON_PRJ, FILE_ICON_SND
119 static const GtkTargetEntry TARGET_ENTRIES_LOCAL_DST[] = {
120 {TEXT_URI_LIST_STD, 0, TARGET_STRING},
121 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET,
122 TARGET_STRING}
127123 };
128124
129 static gchar *ELEKTROID_AUDIO_LOCAL_EXTS[] =
130 { "wav", "ogg", "aiff", "flac", NULL };
131
132 static GtkTargetEntry TARGET_ENTRIES_LOCAL_DST[] = {
133 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET,
134 TARGET_STRING},
135 {TEXT_URI_LIST_STD, GTK_TARGET_SAME_APP | GTK_TARGET_SAME_WIDGET,
136 TARGET_STRING},
137 {TEXT_URI_LIST_STD, GTK_TARGET_OTHER_APP, TARGET_STRING}
125 static const GtkTargetEntry TARGET_ENTRIES_LOCAL_SRC[] = {
126 {TEXT_URI_LIST_STD, 0, TARGET_STRING}
138127 };
139128
140 static GtkTargetEntry TARGET_ENTRIES_LOCAL_SRC[] = {
141 {TEXT_URI_LIST_STD, GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET,
142 TARGET_STRING},
143 {TEXT_URI_LIST_STD, GTK_TARGET_SAME_APP | GTK_TARGET_SAME_WIDGET,
144 TARGET_STRING},
145 {TEXT_URI_LIST_STD, GTK_TARGET_OTHER_APP, TARGET_STRING}
129 static const GtkTargetEntry TARGET_ENTRIES_REMOTE_SYSTEM_DST[] = {
130 {TEXT_URI_LIST_STD, 0, TARGET_STRING}
146131 };
147132
148 static GtkTargetEntry TARGET_ENTRIES_REMOTE_DST[] = {
149 {TEXT_URI_LIST_STD, GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET,
150 TARGET_STRING},
133 static const GtkTargetEntry TARGET_ENTRIES_REMOTE_SYSTEM_SRC[] = {
134 {TEXT_URI_LIST_STD, 0, TARGET_STRING}
135 };
136
137 static const GtkTargetEntry TARGET_ENTRIES_REMOTE_DST[] = {
138 {TEXT_URI_LIST_STD, 0, TARGET_STRING},
151139 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP | GTK_TARGET_SAME_WIDGET,
152140 TARGET_STRING},
153 {TEXT_URI_LIST_STD, GTK_TARGET_OTHER_APP, TARGET_STRING}
154141 };
155142
156 static GtkTargetEntry TARGET_ENTRIES_REMOTE_SRC[] = {
157 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET,
158 TARGET_STRING},
159 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP | GTK_TARGET_SAME_WIDGET,
160 TARGET_STRING}
143 static const GtkTargetEntry TARGET_ENTRIES_REMOTE_DST_SLOT[] = {
144 {TEXT_URI_LIST_STD, 0, TARGET_STRING}
161145 };
162146
163 static GtkTargetEntry TARGET_ENTRIES_UP_BUTTON_DST[] = {
164 {TEXT_URI_LIST_STD, GTK_TARGET_SAME_APP,
165 TARGET_STRING},
166 {TEXT_URI_LIST_STD, GTK_TARGET_OTHER_APP,
167 TARGET_STRING},
168 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP,
169 TARGET_STRING}
147 static const GtkTargetEntry TARGET_ENTRIES_REMOTE_SRC[] = {
148 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP, TARGET_STRING},
170149 };
171150
172 static guint TARGET_ENTRIES_LOCAL_DST_N =
173 G_N_ELEMENTS (TARGET_ENTRIES_LOCAL_DST);
174 static guint TARGET_ENTRIES_LOCAL_SRC_N =
175 G_N_ELEMENTS (TARGET_ENTRIES_LOCAL_SRC);
176 static guint TARGET_ENTRIES_REMOTE_DST_N =
177 G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_DST);
178 static guint TARGET_ENTRIES_REMOTE_SRC_N =
179 G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_SRC);
180 static guint TARGET_ENTRIES_UP_BUTTON_DST_N =
181 G_N_ELEMENTS (TARGET_ENTRIES_UP_BUTTON_DST);
151 static const GtkTargetEntry TARGET_ENTRIES_UP_BUTTON_DST[] = {
152 {TEXT_URI_LIST_STD, 0, TARGET_STRING},
153 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP, TARGET_STRING}
154 };
182155
183156 static struct browser remote_browser;
184157 static struct browser local_browser;
185158
186159 static struct audio audio;
187 static struct connector connector;
160 static struct backend backend;
188161 static struct preferences preferences;
189162
190163 static GThread *load_thread = NULL;
191164 static GThread *task_thread = NULL;
192165 static GThread *sysex_thread = NULL;
193166 static struct elektroid_transfer transfer;
194 static struct connector_sysex_transfer sysex_transfer;
195
196 static GThread *notifier_thread = NULL;
197 struct notifier notifier;
167 static struct sysex_transfer sysex_transfer;
198168
199169 static GtkWidget *main_window;
200170 static GtkAboutDialog *about_dialog;
209179 static GtkWidget *tx_sysex_button;
210180 static GtkWidget *os_upgrade_button;
211181 static GtkWidget *about_button;
182 static GtkWidget *local_box;
212183 static GtkWidget *remote_box;
213184 static GtkWidget *waveform_draw_area;
214185 static GtkStatusbar *status_bar;
215186 static GtkListStore *devices_list_store;
216 static GtkComboBox *devices_combo;
187 static GtkWidget *devices_combo;
188 static GtkWidget *local_audio_box;
217189 static GtkWidget *upload_menuitem;
218 static GtkWidget *local_audio_box;
190 static GtkWidget *local_play_separator;
219191 static GtkWidget *local_play_menuitem;
220192 static GtkWidget *local_open_menuitem;
221193 static GtkWidget *local_show_menuitem;
222194 static GtkWidget *local_rename_menuitem;
223195 static GtkWidget *local_delete_menuitem;
224196 static GtkWidget *download_menuitem;
197 static GtkWidget *remote_play_separator;
198 static GtkWidget *remote_play_menuitem;
199 static GtkWidget *remote_options_separator;
200 static GtkWidget *remote_open_menuitem;
201 static GtkWidget *remote_show_menuitem;
202 static GtkWidget *remote_actions_separator;
225203 static GtkWidget *remote_rename_menuitem;
226204 static GtkWidget *remote_delete_menuitem;
227205 static GtkWidget *play_button;
228206 static GtkWidget *stop_button;
207 static GtkWidget *loop_button;
208 static GtkWidget *autoplay_switch;
209 static GtkWidget *mix_switch;
229210 static GtkWidget *volume_button;
211 static gulong volume_changed_handler;
230212 static GtkListStore *task_list_store;
231213 static GtkWidget *task_tree_view;
232214 static GtkWidget *cancel_task_button;
233215 static GtkWidget *remove_tasks_button;
234216 static GtkWidget *clear_tasks_button;
235217 static GtkListStore *fs_list_store;
236 static GtkComboBox *fs_combo;
237 static GtkTreeViewColumn *remote_tree_view_index_column;
238
239 static const gchar *
240 elektroid_get_fs_name (enum connector_fs fs)
241 {
242 switch (fs)
243 {
244 case FS_SAMPLES:
245 return _("Samples");
246 case FS_RAW_PRESETS:
247 return _("Presets");
248 case FS_DATA_PRJ:
249 return _("Projects");
250 case FS_DATA_SND:
251 return _("Sounds");
252 default:
253 return _("Undefined");
254 }
255 }
256
257 static void
258 elektroid_set_file_extensions_for_fs (gchar ** extensions[],
259 enum connector_fs sel_fs)
260 {
261 const struct fs_operations *ops;
262 gchar *mp3_ext = NULL;
263
264 if (*extensions != NULL)
265 {
266 gchar **ext = *extensions;
267 while (*ext)
268 {
269 g_free (*ext);
270 ext++;
271 }
272 g_free (*extensions);
273 }
274
275 if (sel_fs == FS_SAMPLES)
276 {
277 gchar **ext = ELEKTROID_AUDIO_LOCAL_EXTS;
278 int known_ext = 0;
279 while (*ext)
280 {
281 known_ext++;
282 ext++;
283 }
284 known_ext++; //NULL included
285
286 int total_ext = known_ext;
287
288 if (sample_is_mp3_supported ())
289 {
290 mp3_ext = "mp3";
291 total_ext++;
292 }
293
294 *extensions = malloc (sizeof (gchar *) * total_ext);
295 ext = ELEKTROID_AUDIO_LOCAL_EXTS;
296 int i = 0;
297 while (*ext)
298 {
299 (*extensions)[i] = strdup (*ext);
300 ext++;
301 i++;
302 }
303 if (mp3_ext)
304 {
305 (*extensions)[i] = strdup (mp3_ext);
306 i++;
307 }
308 (*extensions)[i] = NULL;
309
218 static GtkWidget *fs_combo;
219 static GtkTreeViewColumn *remote_tree_view_id_column;
220 static GtkTreeViewColumn *remote_tree_view_slot_column;
221 static GtkTreeViewColumn *remote_tree_view_size_column;
222 static GtkWidget *sample_info_box;
223 static GtkWidget *sample_length;
224 static GtkWidget *sample_duration;
225 static GtkWidget *sample_channels;
226 static GtkWidget *sample_samplerate;
227 static GtkWidget *sample_bitdepth;
228 static gchar **dnd_uris;
229 static gchar *dnd_type_name;
230
231 inline static const gchar *
232 elektroid_get_fs_name (guint fs)
233 {
234 return backend_get_fs_operations (&backend, fs, NULL)->gui_name;
235 }
236
237 static void
238 elektroid_clear_file_extensions (gchar *** extensions)
239 {
240 if (*extensions == NULL)
241 {
242 return;
243 }
244
245 gchar **ext = *extensions;
246 while (*ext)
247 {
248 g_free (*ext);
249 ext++;
250 }
251 g_free (*extensions);
252
253 *extensions = NULL;
254 }
255
256 static void
257 elektroid_set_file_extensions (gchar *** ext_dst, const gchar ** ext_src)
258 {
259 const gchar **ext = ext_src;
260 int ext_count = 0;
261 while (*ext)
262 {
263 ext_count++;
264 ext++;
265 }
266 ext_count++; //NULL included
267
268 *ext_dst = malloc (sizeof (gchar *) * ext_count);
269 ext = ext_src;
270 int i = 0;
271 while (*ext)
272 {
273 (*ext_dst)[i] = strdup (*ext);
274 ext++;
275 i++;
276 }
277 (*ext_dst)[i] = NULL;
278 }
279
280 static void
281 elektroid_set_file_extension (gchar *** ext_dst, gchar * ext)
282 {
283 *ext_dst = malloc (sizeof (gchar *) * 2);
284 (*ext_dst)[0] = ext;
285 (*ext_dst)[1] = NULL;
286 }
287
288 static void
289 elektroid_set_local_file_extensions (gint sel_fs)
290 {
291 const struct fs_operations *ops =
292 backend_get_fs_operations (&backend, sel_fs, NULL);
293
294 elektroid_clear_file_extensions (&local_browser.extensions);
295
296 if (!ops || (ops->options & FS_OPTION_AUDIO_PLAYER))
297 {
298 elektroid_set_file_extensions (&local_browser.extensions,
299 sample_get_sample_extensions ());
310300 }
311301 else
312302 {
313 ops = connector_get_fs_operations (sel_fs);
314 *extensions = malloc (sizeof (gchar *) * 2);
315 (*extensions)[0] = connector_get_full_ext (&connector.device_desc, ops);
316 (*extensions)[1] = NULL;
317 }
318 }
319
320 static const gchar *
321 elektroid_get_inventory_icon_for_fs (enum connector_fs sel_fs)
322 {
323 const gchar *icon = FILE_ICON_DATA;
324
325 for (int fs = FS_SAMPLES, i = 0; fs <= FS_DATA_SND; fs <<= 1, i++)
326 {
327 if (GUI_FSS & fs && sel_fs == fs)
328 {
329 icon = ELEKTROID_FS_ICONS[i];
330 break;
331 }
332 }
333 return icon;
303 elektroid_set_file_extension (&local_browser.extensions,
304 ops->get_ext (&backend.device_desc, ops));
305 }
306 }
307
308 static void
309 elektroid_set_remote_file_extensions (gint sel_fs)
310 {
311 const struct fs_operations *ops =
312 backend_get_fs_operations (&backend, sel_fs, NULL);
313
314 elektroid_clear_file_extensions (&remote_browser.extensions);
315
316 if (ops && backend.type == BE_TYPE_SYSTEM)
317 {
318 elektroid_set_file_extension (&remote_browser.extensions,
319 ops->get_ext (&backend.device_desc, ops));
320 }
334321 }
335322
336323 static void
354341 }
355342
356343 static void
344 elektroid_set_widget_source (GtkWidget * widget, enum audio_src audio_src)
345 {
346 const char *class;
347 GtkStyleContext *context = gtk_widget_get_style_context (widget);
348 GList *classes, *list = gtk_style_context_list_classes (context);
349
350 for (classes = list; classes != NULL; classes = g_list_next (classes))
351 {
352 gtk_style_context_remove_class (context, classes->data);
353 }
354 g_list_free (list);
355
356 if (audio_src == AUDIO_SRC_NONE)
357 {
358 return;
359 }
360
361 if (GTK_IS_SWITCH (widget))
362 {
363 class = audio_src == AUDIO_SRC_LOCAL ? "local_switch" : "remote_switch";
364 }
365 else
366 {
367 class = audio_src == AUDIO_SRC_LOCAL ? "local" : "remote";
368 }
369 gtk_style_context_add_class (context, class);
370 }
371
372 static void
373 elektroid_set_player_source (enum audio_src audio_src)
374 {
375 elektroid_set_widget_source (autoplay_switch, audio_src);
376 elektroid_set_widget_source (mix_switch, audio_src);
377 elektroid_set_widget_source (play_button, audio_src);
378 elektroid_set_widget_source (stop_button, audio_src);
379 elektroid_set_widget_source (loop_button, audio_src);
380 elektroid_set_widget_source (volume_button, audio_src);
381 elektroid_set_widget_source (waveform_draw_area, audio_src);
382 }
383
384 static gboolean
385 elektroid_load_remote_if_midi (gpointer data)
386 {
387 struct browser *browser = data;
388 if (browser == &remote_browser && backend.type == BE_TYPE_MIDI)
389 {
390 browser_load_dir (browser);
391 }
392 return FALSE;
393 }
394
395 static void
396 elektroid_update_upload_menuitem ()
397 {
398 gboolean slot = remote_browser.fs_ops &&
399 !(remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE);
400
401 gtk_widget_set_visible (upload_menuitem, slot);
402 gtk_widget_set_visible (local_play_separator, slot);
403 }
404
405 static void
357406 elektroid_load_devices (gboolean auto_select)
358407 {
359408 gint i;
360409 gint device_index;
361 GArray *devices = connector_get_system_devices ();
362 struct connector_system_device device;
410 gchar hostname[LABEL_MAX];
411 GArray *devices = backend_get_system_devices ();
412 struct backend_system_device device;
363413
364414 debug_print (1, "Loading devices...\n");
365415
366416 gtk_list_store_clear (fs_list_store);
367417 gtk_list_store_clear (devices_list_store);
368418
419 gethostname (hostname, LABEL_MAX);
420 gtk_list_store_insert_with_values (devices_list_store, NULL, -1,
421 DEVICES_LIST_STORE_ID_FIELD,
422 BE_SYSTEM_ID,
423 DEVICES_LIST_STORE_NAME_FIELD,
424 hostname, -1);
425
369426 for (i = 0; i < devices->len; i++)
370427 {
371 device = g_array_index (devices, struct connector_system_device, i);
428 device = g_array_index (devices, struct backend_system_device, i);
372429 gtk_list_store_insert_with_values (devices_list_store, NULL, -1,
373 DEVICES_LIST_STORE_CARD_FIELD,
374 device.card,
430 DEVICES_LIST_STORE_ID_FIELD,
431 device.id,
375432 DEVICES_LIST_STORE_NAME_FIELD,
376433 device.name, -1);
377434 }
435 i++; //We add the system backend.
378436
379437 g_array_free (devices, TRUE);
380438
381439 device_index = auto_select && i == 1 ? 0 : -1;
382440 debug_print (1, "Selecting device %d...\n", device_index);
383 gtk_combo_box_set_active (devices_combo, device_index);
441 gtk_combo_box_set_active (GTK_COMBO_BOX (devices_combo), device_index);
384442
385443 if (device_index == -1)
386444 {
387 local_browser.file_icon =
388 elektroid_get_inventory_icon_for_fs (FS_SAMPLES);
389 elektroid_set_file_extensions_for_fs (&local_browser.extensions,
390 FS_SAMPLES);
391
445 local_browser.file_icon = BE_FILE_ICON_WAVE;
446 elektroid_set_local_file_extensions (0);
392447 gtk_widget_set_visible (local_audio_box, TRUE);
393 gtk_tree_view_column_set_visible (remote_tree_view_index_column, FALSE);
394
448 gtk_tree_view_column_set_visible (remote_tree_view_id_column, FALSE);
449 gtk_tree_view_column_set_visible (remote_tree_view_slot_column, FALSE);
450 gtk_tree_view_column_set_visible (remote_tree_view_size_column, FALSE);
395451 browser_load_dir (&local_browser);
396 }
452 elektroid_update_upload_menuitem ();
453 }
454 }
455
456 static gboolean
457 elektroid_load_devices_bg (gpointer data)
458 {
459 gboolean visible;
460 GValue value = G_VALUE_INIT;
461
462 g_object_get_property (G_OBJECT (main_window), "visible", &value);
463 visible = g_value_get_boolean (&value);
464
465 if (visible)
466 {
467 elektroid_load_devices (TRUE); //This triggers a local browser reload due to the extensions and icons selected for the fs
468 return FALSE;
469 }
470
471 return TRUE;
397472 }
398473
399474 static void
401476 {
402477 gchar *status;
403478 gchar *statfss_str;
404 gint res;
405 enum connector_storage storage;
406 struct connector_storage_stats statfs;
479 struct backend_storage_stats statfs;
407480 GString *statfss;
408481
409482 gtk_statusbar_pop (status_bar, 0);
410483
411 if (connector_check (&connector))
484 if (backend_check (&backend))
412485 {
413486 statfss = g_string_new (NULL);
414
415 for (storage = STORAGE_PLUS_DRIVE; storage <= STORAGE_RAM;
416 storage <<= 1)
417 {
418 if (connector.device_desc.storage & storage)
487 if (backend.get_storage_stats)
488 {
489 for (gint i = 0, storage = 1; i < MAX_BACKEND_STORAGE;
490 i++, storage <<= 1)
419491 {
420 res =
421 connector_get_storage_stats (&connector, storage, &statfs);
422 if (!res)
492 if (backend.device_desc.storage & storage)
423493 {
424 g_string_append_printf (statfss, " %s %.2f%%",
425 statfs.name,
426 connector_get_storage_stats_percent
427 (&statfs));
494 if (!backend.get_storage_stats (&backend, storage, &statfs))
495 {
496 g_string_append_printf (statfss, " %s %.2f%%",
497 statfs.name,
498 backend_get_storage_stats_percent
499 (&statfs));
500 }
428501 }
429502 }
430503 }
504
431505 statfss_str = g_string_free (statfss, FALSE);
432 status = malloc (LABEL_MAX);
433 snprintf (status, LABEL_MAX, _("Connected to %s%s"),
434 connector.device_name, statfss_str);
506 status = g_malloc (LABEL_MAX);
507 if (strlen (backend.device_name))
508 {
509 snprintf (status, LABEL_MAX, "%s%s", backend.device_name,
510 statfss_str);
511 }
512 else
513 {
514 status[0] = 0;
515 }
435516 gtk_statusbar_push (status_bar, 0, status);
436517 free (status);
437518 g_free (statfss_str);
482563 }
483564
484565 static gboolean
485 elektroid_check_connector ()
566 elektroid_check_backend ()
486567 {
487568 GtkListStore *list_store;
488569 GtkTreeIter iter;
489 gboolean connected = connector_check (&connector);
490 gboolean queued =
491 elektroid_get_next_queued_task (&iter, NULL, NULL, NULL, NULL);
492
493 gtk_widget_set_sensitive (remote_box, connected);
570 gboolean remote_sensitive;
571 gboolean connected = backend_check (&backend);
572 gboolean queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL,
573 NULL);
574
575 elektroid_update_upload_menuitem ();
576
577 if (!remote_browser.fs_ops
578 || remote_browser.fs_ops->options & FS_OPTION_SINGLE_OP)
579 {
580 remote_sensitive = connected && !queued;
581 }
582 else
583 {
584 remote_sensitive = connected;
585 }
586 gtk_widget_set_sensitive (remote_box, remote_sensitive);
587 gtk_widget_set_sensitive (upload_menuitem, remote_sensitive);
494588 gtk_widget_set_sensitive (rx_sysex_button, connected && !queued);
495589 gtk_widget_set_sensitive (tx_sysex_button, connected && !queued);
496 gtk_widget_set_sensitive (os_upgrade_button, connected && !queued);
590 gtk_widget_set_sensitive (os_upgrade_button, connected && !queued
591 && backend.upgrade_os);
497592
498593 if (!connected)
499594 {
501596 GTK_LIST_STORE (gtk_tree_view_get_model (remote_browser.view));
502597 gtk_entry_set_text (remote_browser.dir_entry, "");
503598 gtk_list_store_clear (list_store);
504
505599 elektroid_load_devices (FALSE);
506600 }
507601
511605 }
512606
513607 static gboolean
514 elektroid_check_connector_bg (gpointer data)
515 {
516 elektroid_check_connector ();
517
608 elektroid_check_backend_bg (gpointer data)
609 {
610 elektroid_check_backend ();
518611 return FALSE;
519612 }
520613
521614 static void
522 browser_refresh_devices (GtkWidget * object, gpointer data)
523 {
524 if (connector_check (&connector))
525 {
526 connector_destroy (&connector);
527 elektroid_check_connector ();
528 }
529 elektroid_load_devices (FALSE);
615 elektroid_cancel_all_tasks_and_wait ()
616 {
617 elektroid_cancel_all_tasks (NULL, NULL);
618 //In this case, the active waiting can not be avoided as the user has cancelled the operation.
619 while (transfer.status == RUNNING)
620 {
621 usleep (50000);
622 }
623 }
624
625 static void
626 elektroid_refresh_devices (GtkWidget * object, gpointer data)
627 {
628 if (backend_check (&backend))
629 {
630 elektroid_cancel_all_tasks_and_wait ();
631 backend_destroy (&backend);
632 elektroid_reset_sample (&remote_browser);
633 remote_browser.fs_ops = NULL;
634 }
635 elektroid_check_backend (); //This triggers the actual devices refresh if there is no backend
530636 }
531637
532638 static gpointer
561667 }
562668
563669 static void
564 elektroid_progress_dialog_end (gpointer data)
565 {
670 elektroid_progress_dialog_close (gpointer data)
671 {
672 gtk_label_set_text (GTK_LABEL (progress_label), _("Cancelling..."));
566673 elektroid_cancel_running_sysex (NULL, 0, NULL);
567674 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_CANCEL);
568675 }
572679 {
573680 gchar *text;
574681 gboolean active;
575 enum connector_sysex_transfer_status status;
682 enum sysex_transfer_status status;
683
684 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress_bar));
576685
577686 g_mutex_lock (&sysex_transfer.mutex);
578687 status = sysex_transfer.status;
585694 break;
586695 case SENDING:
587696 text = _("Sending...");
588 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress_bar));
589697 break;
590698 case RECEIVING:
591699 text = _("Receiving...");
592 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress_bar));
593700 break;
594701 default:
595702 text = "";
611718
612719 sysex_transfer.status = WAITING;
613720 sysex_transfer.active = TRUE;
614 sysex_transfer.timeout = DUMP_TIMEOUT;
721 sysex_transfer.timeout = BE_DUMP_TIMEOUT;
615722 sysex_transfer.batch = TRUE;
616723
617724 g_timeout_add (100, elektroid_update_sysex_progress, NULL);
618725
619 connector_rx_drain (&connector);
620 *res = connector_rx_sysex (&connector, &sysex_transfer);
726 backend_rx_drain (&backend);
727 //This doesn't need to be synchronized because the GUI doesn't allow concurrent access when receiving SysEx in batch mode.
728 *res = backend_rx_sysex (&backend, &sysex_transfer);
621729 if (!*res)
622730 {
623731 text = debug_get_hex_msg (sysex_transfer.raw);
629737 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_ACCEPT);
630738
631739 return res;
632 }
633
634 static gboolean
635 elektroid_start_rx_thread (gpointer data)
636 {
637 debug_print (1, "Creating rx SysEx thread...\n");
638 sysex_thread =
639 g_thread_new ("sysex_thread", elektroid_rx_sysex_thread, NULL);
640
641 return FALSE;
642740 }
643741
644742 static void
654752 gint *res;
655753 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
656754
657 g_idle_add (elektroid_start_rx_thread, NULL);
755 debug_print (1, "Creating rx SysEx thread...\n");
756 sysex_thread = g_thread_new ("sysex_thread", elektroid_rx_sysex_thread,
757 NULL);
658758
659759 gtk_window_set_title (GTK_WINDOW (progress_dialog), _("Receive SysEx"));
660760 dres = gtk_dialog_run (GTK_DIALOG (progress_dialog));
761 g_mutex_lock (&sysex_transfer.mutex);
661762 sysex_transfer.active = FALSE;
763 g_mutex_unlock (&sysex_transfer.mutex);
662764 gtk_widget_hide (GTK_WIDGET (progress_dialog));
663765
664766 res = elektroid_join_sysex_thread ();
767
768 if (!res) //Signal captured while running the dialog.
769 {
770 g_byte_array_free (sysex_transfer.raw, TRUE);
771 return;
772 }
665773
666774 if (dres != GTK_RESPONSE_ACCEPT)
667775 {
675783
676784 if (*res)
677785 {
678 elektroid_check_connector ();
786 elektroid_check_backend ();
679787 g_free (res);
680788 return;
681789 }
729837 if (*res)
730838 {
731839 show_error_msg (_("Error while saving “%s”: %s."),
732 filename, g_strerror (*res));
840 filename, g_strerror (-*res));
733841 }
734842 g_byte_array_free (sysex_transfer.raw, TRUE);
735843 g_free (res);
739847 gtk_widget_destroy (dialog);
740848 }
741849
850 static gint
851 elektroid_send_sysex_file (const gchar * filename, t_sysex_transfer f)
852 {
853 gint err = load_file (filename, sysex_transfer.raw, NULL);
854 if (!err)
855 {
856 err = f (&backend, &sysex_transfer);
857 }
858 if (err && err != -ECANCELED)
859 {
860 show_error_msg (_("Error while loading “%s”: %s."),
861 filename, g_strerror (-err));
862 }
863 return err;
864 }
865
742866 static gpointer
743 elektroid_tx_sysex_thread (gpointer data)
744 {
745 gchar *text;
746 gint *res = malloc (sizeof (gint));
747 connector_send_raw f = data;
748
867 elektroid_tx_sysex_files_thread (gpointer data)
868 {
869 GSList *filenames = data;
870 gint *err = malloc (sizeof (gint));
871 sysex_transfer.raw = g_byte_array_new ();
749872 sysex_transfer.active = TRUE;
750 sysex_transfer.timeout = SYSEX_TIMEOUT;
873 sysex_transfer.status = SENDING;
751874
752875 g_timeout_add (100, elektroid_update_sysex_progress, NULL);
753876
754 *res = f (&connector, &sysex_transfer);
755 if (!*res)
756 {
757 text = debug_get_hex_msg (sysex_transfer.raw);
758 debug_print (1, "SysEx message sent (%d): %s\n",
759 sysex_transfer.raw->len, text);
760 free (text);
761 }
762
763 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_CANCEL);
764
765 return res;
766 }
767
768 static void
769 elektroid_tx_sysex_common (connector_send_raw f)
877 *err = 0;
878 while (*err != -ECANCELED && filenames)
879 {
880 g_byte_array_set_size (sysex_transfer.raw, 0);
881 *err = elektroid_send_sysex_file (filenames->data,
882 backend_tx_sysex_no_update);
883 filenames = filenames->next;
884 //The device may have sent some messages in response so we skip all these.
885 backend_rx_drain (&backend);
886 usleep (BE_REST_TIME_US);
887 }
888 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_CANCEL); //Any response is OK.
889
890 free_msg (sysex_transfer.raw);
891 return err;
892 }
893
894 static gpointer
895 elektroid_tx_upgrade_os_thread (gpointer data)
896 {
897 GSList *filenames = data;
898 gint *err = malloc (sizeof (gint));
899 sysex_transfer.raw = g_byte_array_new ();
900 sysex_transfer.timeout = BE_SYSEX_TIMEOUT_MS;
901
902 g_timeout_add (100, elektroid_update_sysex_progress, NULL);
903
904 *err = elektroid_send_sysex_file (filenames->data, backend.upgrade_os);
905 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_CANCEL); //Any response is OK.
906
907 free_msg (sysex_transfer.raw);
908
909 return err;
910 }
911
912 static void
913 elektroid_tx_sysex_common (GThreadFunc func, gboolean multiple)
770914 {
771915 GtkWidget *dialog;
772916 GtkFileChooser *chooser;
773917 GtkFileFilter *filter;
774 gint res, lres;
775 char *filename;
776 gint *response;
777 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
918 gint res, *err;
919 GSList *filenames;
778920
779921 dialog = gtk_file_chooser_dialog_new (_("Open SysEx"),
780922 GTK_WINDOW (main_window),
781 action,
923 GTK_FILE_CHOOSER_ACTION_OPEN,
782924 _("_Cancel"),
783925 GTK_RESPONSE_CANCEL,
784926 _("_Open"),
788930 gtk_file_filter_set_name (filter, _("SysEx Files"));
789931 gtk_file_filter_add_pattern (filter, "*.syx");
790932 gtk_file_chooser_add_filter (chooser, filter);
933 gtk_file_chooser_set_current_folder (chooser, preferences.local_dir);
934 gtk_file_chooser_set_select_multiple (chooser, multiple);
791935
792936 res = gtk_dialog_run (GTK_DIALOG (dialog));
793
794937 if (res == GTK_RESPONSE_ACCEPT)
795938 {
796 filename = gtk_file_chooser_get_filename (chooser);
797 gtk_widget_destroy (dialog);
798 debug_print (1, "Opening SysEx file...\n");
799
800 sysex_transfer.raw = g_byte_array_new ();
801
802 lres = load_file (filename, sysex_transfer.raw, NULL);
803 if (lres)
804 {
805 show_error_msg (_("Error while loading “%s”: %s."),
806 filename, g_strerror (lres));
807 response = NULL;
808 }
809 else
810 {
811 sysex_thread =
812 g_thread_new ("sysex_thread", elektroid_tx_sysex_thread, f);
813
814 gtk_window_set_title (GTK_WINDOW (progress_dialog),
815 _("Send SysEx"));
816 res = gtk_dialog_run (GTK_DIALOG (progress_dialog));
817
818 g_mutex_lock (&sysex_transfer.mutex);
819 sysex_transfer.active = FALSE;
820 g_mutex_unlock (&sysex_transfer.mutex);
821
822 gtk_widget_hide (GTK_WIDGET (progress_dialog));
823
824 response = elektroid_join_sysex_thread ();
825 }
826
827 g_byte_array_free (sysex_transfer.raw, TRUE);
828
829
830 if (*response < 0)
831 {
832 elektroid_check_connector ();
833 }
834
835 free (response);
836 }
837 else
838 {
839 gtk_widget_destroy (dialog);
840 }
939 gtk_widget_hide (GTK_WIDGET (dialog));
940 filenames = gtk_file_chooser_get_filenames (chooser);
941 sysex_thread = g_thread_new ("sysex_thread", func, filenames);
942 gtk_window_set_title (GTK_WINDOW (progress_dialog), _("Sending SysEx"));
943 gtk_dialog_run (GTK_DIALOG (progress_dialog));
944
945 //If the progress_dialog is closed, we end the transfer.
946 g_mutex_lock (&sysex_transfer.mutex);
947 sysex_transfer.active = FALSE;
948 g_mutex_unlock (&sysex_transfer.mutex);
949
950 gtk_widget_hide (GTK_WIDGET (progress_dialog));
951 err = elektroid_join_sysex_thread ();
952
953 g_slist_free_full (g_steal_pointer (&filenames), g_free);
954
955 if (!err) //Signal captured while running the dialog.
956 {
957 goto cleanup;
958 }
959
960 if (*err < 0)
961 {
962 elektroid_check_backend ();
963 }
964
965 g_free (err);
966 }
967
968 cleanup:
969 gtk_widget_destroy (dialog);
841970 }
842971
843972 static void
844973 elektroid_tx_sysex (GtkWidget * object, gpointer data)
845974 {
846 elektroid_tx_sysex_common (connector_tx_sysex);
975 elektroid_tx_sysex_common (elektroid_tx_sysex_files_thread, TRUE);
847976 }
848977
849978 static void
850979 elektroid_upgrade_os (GtkWidget * object, gpointer data)
851980 {
852 elektroid_tx_sysex_common (connector_upgrade_os);
853 connector_destroy (&connector);
854 elektroid_check_connector ();
981 elektroid_tx_sysex_common (elektroid_tx_upgrade_os_thread, FALSE);
982 backend_destroy (&backend);
983 elektroid_check_backend ();
855984 }
856985
857986 static void
862991 }
863992
864993 static void
865 elektroid_sample_controls_set_sensitive (gboolean sensitive)
866 {
867 gtk_widget_set_sensitive (local_play_menuitem, sensitive);
994 elektroid_set_sample_properties_on_load ()
995 {
996 double time;
997 gchar label[LABEL_MAX];
998 struct sample_info *sample_info = audio.control.data;
999
1000 gtk_widget_set_visible (sample_info_box, sample_info->frames > 0);
1001
1002 if (!sample_info->frames)
1003 {
1004 return;
1005 }
1006
1007 time = sample_info->frames / (double) sample_info->samplerate;
1008
1009 gtk_widget_set_visible (sample_info_box, TRUE);
1010
1011 snprintf (label, LABEL_MAX, "%d", sample_info->frames);
1012 gtk_label_set_text (GTK_LABEL (sample_length), label);
1013
1014 if (time >= 60)
1015 {
1016 snprintf (label, LABEL_MAX, "%.2f %s", time / 60.0, _("minutes"));
1017 }
1018 else
1019 {
1020 snprintf (label, LABEL_MAX, "%.2f s", time);
1021 }
1022 gtk_label_set_text (GTK_LABEL (sample_duration), label);
1023
1024 snprintf (label, LABEL_MAX, "%.2f kHz", sample_info->samplerate / 1000.f);
1025 gtk_label_set_text (GTK_LABEL (sample_samplerate), label);
1026
1027 snprintf (label, LABEL_MAX, "%d", sample_info->channels);
1028 gtk_label_set_text (GTK_LABEL (sample_channels), label);
1029
1030 if (sample_info->bitdepth)
1031 {
1032 snprintf (label, LABEL_MAX, "%d", sample_info->bitdepth);
1033 gtk_label_set_text (GTK_LABEL (sample_bitdepth), label);
1034 }
1035 }
1036
1037 static void
1038 elektroid_set_audio_controls_on_load (gboolean sensitive)
1039 {
1040 gtk_widget_set_sensitive (local_play_menuitem,
1041 audio.src == AUDIO_SRC_LOCAL);
1042 gtk_widget_set_sensitive (remote_play_menuitem,
1043 audio.src == AUDIO_SRC_REMOTE);
8681044 gtk_widget_set_sensitive (play_button, sensitive);
8691045 gtk_widget_set_sensitive (stop_button, sensitive);
8701046 }
8731049 elektroid_update_ui_on_load (gpointer data)
8741050 {
8751051 gboolean ready_to_play;
1052 struct sample_info *sample_info = audio.control.data;
8761053
8771054 g_mutex_lock (&audio.control.mutex);
8781055 ready_to_play = audio.frames >= LOAD_BUFFER_LEN || (!audio.control.active
8791056 && audio.frames > 0);
1057 audio.channels = PLAYER_LOADED_CHANNELS;
8801058 g_mutex_unlock (&audio.control.mutex);
8811059
1060 elektroid_set_sample_properties_on_load ();
1061
8821062 if (ready_to_play)
8831063 {
8841064 if (audio_check (&audio))
8851065 {
886 elektroid_sample_controls_set_sensitive (TRUE);
1066 elektroid_set_audio_controls_on_load (TRUE);
8871067 }
8881068 if (preferences.autoplay)
8891069 {
8951075 return TRUE;
8961076 }
8971077
898 static void
899 elektroid_delete_file (GtkTreeModel * model, GtkTreePath * tree_path,
900 struct browser *browser)
901 {
902 GtkTreeIter iter;
1078 static gboolean
1079 elektroid_update_basic_sysex_progress (gpointer data)
1080 {
1081 gboolean active;
1082
1083 g_mutex_lock (&sysex_transfer.mutex);
1084 active = sysex_transfer.active;
1085 g_mutex_unlock (&sysex_transfer.mutex);
1086
1087 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress_bar));
1088
1089 return active;
1090 }
1091
1092 static gint
1093 elektroid_delete_file (struct browser *browser, gchar * dir,
1094 struct item *item)
1095 {
1096 gint err = 0;
9031097 gchar *path;
904 gchar *id_path;
905 gint err;
906 struct item *item;
907
908 gtk_tree_model_get_iter (model, &iter, tree_path);
909 item = browser_get_item (model, &iter);
910 path = browser_get_item_path (browser, item);
911 id_path = browser_get_item_id_path (browser, item);
912
913 debug_print (1, "Deleting %s...\n", id_path);
914 err = browser->fs_ops->delete (id_path, browser->data);
915 if (err)
916 {
917 show_error_msg (_("Error while deleting “%s”: %s."),
918 path, g_strerror (err));
919 }
920 else
921 {
922 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
923 }
924
1098
1099 path = chain_path (dir, item->name);
1100
1101 debug_print (1, "Deleting %s...\n", path);
1102
1103 if (item->type == ELEKTROID_FILE)
1104 {
1105 gchar *filename = get_filename (browser->fs_ops->options, item);
1106 gchar *id_path = chain_path (dir, filename);
1107 g_free (filename);
1108 err = browser->fs_ops->delete (browser->backend, id_path);
1109 if (err)
1110 {
1111 error_print ("Error while deleting “%s”: %s.\n", path,
1112 g_strerror (-err));
1113 }
1114 g_free (id_path);
1115 }
1116 else if (item->type == ELEKTROID_DIR)
1117 {
1118 gboolean active;
1119 struct item_iterator iter;
1120 if (browser->fs_ops->readdir (browser->backend, &iter, path))
1121 {
1122 err = -ENOTDIR;
1123 goto end;
1124 }
1125
1126 while (!next_item_iterator (&iter))
1127 {
1128 elektroid_delete_file (browser, path, &iter.item);
1129
1130 g_mutex_lock (&sysex_transfer.mutex);
1131 active = sysex_transfer.active;
1132 g_mutex_unlock (&sysex_transfer.mutex);
1133
1134 if (!active)
1135 {
1136 free_item_iterator (&iter);
1137 err = -ECANCELED;
1138 goto end;
1139 }
1140 }
1141
1142 browser->fs_ops->delete (browser->backend, path);
1143 free_item_iterator (&iter);
1144 }
1145
1146 end:
9251147 g_free (path);
926 g_free (id_path);
927 browser_free_item (item);
928 }
929
930 static void
931 elektroid_delete_files (GtkWidget * object, gpointer data)
932 {
933 GtkTreeRowReference *reference;
934 GList *list;
935 GtkTreePath *tree_path;
1148 return err;
1149 }
1150
1151 static gpointer
1152 elektroid_delete_files_runner (gpointer data)
1153 {
1154 GList *list, *tree_path_list, *ref_list;
9361155 GtkTreeSelection *selection;
9371156 GtkTreeModel *model;
938 GtkWidget *dialog;
939 GList *tree_path_list;
940 GList *ref_list;
1157 struct browser *browser = data;
1158
1159 g_timeout_add (100, elektroid_update_basic_sysex_progress, NULL);
1160
1161 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view));
1162 model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view));
1163 tree_path_list = gtk_tree_selection_get_selected_rows (selection, &model);
1164 ref_list = NULL;
1165
1166 //A GtkTreeModel object can NOT be modified while iterating over the selection.
1167 list = tree_path_list;
1168 while (list)
1169 {
1170 GtkTreeRowReference *ref = gtk_tree_row_reference_new (model,
1171 list->data);
1172 ref_list = g_list_append (ref_list, ref);
1173
1174 list = g_list_next (list);
1175 }
1176 g_list_free_full (tree_path_list, (GDestroyNotify) gtk_tree_path_free);
1177
1178 g_mutex_lock (&browser->mutex);
1179 list = ref_list;
1180 while (list)
1181 {
1182 gboolean active;
1183 GtkTreeIter iter;
1184 struct item item;
1185 GtkTreePath *tree_path = gtk_tree_row_reference_get_path (list->data);
1186
1187 gtk_tree_model_get_iter (model, &iter, tree_path);
1188 browser_set_item (model, &iter, &item);
1189
1190 if (!elektroid_delete_file (browser, browser->dir, &item) &&
1191 browser == &remote_browser &&
1192 browser->backend->type != BE_TYPE_SYSTEM)
1193 {
1194 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1195 }
1196
1197 g_mutex_lock (&sysex_transfer.mutex);
1198 active = sysex_transfer.active;
1199 g_mutex_unlock (&sysex_transfer.mutex);
1200
1201 if (!active)
1202 {
1203 break;
1204 }
1205
1206 list = g_list_next (list);
1207 }
1208 g_list_free_full (ref_list, (GDestroyNotify) gtk_tree_row_reference_free);
1209 g_mutex_unlock (&browser->mutex);
1210
1211 sleep (1); //See elektroid_dnd_received_runner
1212 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_ACCEPT);
1213 return NULL;
1214 }
1215
1216 static void
1217 elektroid_delete_files (GtkWidget * object, gpointer data)
1218 {
9411219 gint confirmation;
942 struct browser *browser = data;
943
944 dialog =
945 gtk_message_dialog_new (GTK_WINDOW (main_window),
946 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
947 GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
948 _
949 ("Are you sure you want to delete the selected items?"));
1220 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1221 GTK_DIALOG_DESTROY_WITH_PARENT |
1222 GTK_DIALOG_MODAL,
1223 GTK_MESSAGE_ERROR,
1224 GTK_BUTTONS_NONE,
1225 _
1226 ("Are you sure you want to delete the selected items?"));
9501227 gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"),
9511228 GTK_RESPONSE_CANCEL, _("_Delete"),
9521229 GTK_RESPONSE_ACCEPT, NULL);
9581235 return;
9591236 }
9601237
961 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view));
962 model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view));
963 tree_path_list = gtk_tree_selection_get_selected_rows (selection, &model);
964 ref_list = NULL;
965
966 for (list = tree_path_list; list != NULL; list = g_list_next (list))
967 {
968 reference = gtk_tree_row_reference_new (model, list->data);
969 ref_list = g_list_append (ref_list, reference);
970 }
971 g_list_free_full (tree_path_list, (GDestroyNotify) gtk_tree_path_free);
972
973 for (list = ref_list; list != NULL; list = g_list_next (list))
974 {
975 tree_path = gtk_tree_row_reference_get_path (list->data);
976 elektroid_delete_file (model, tree_path, browser);
977 }
978 g_list_free_full (ref_list, (GDestroyNotify) gtk_tree_row_reference_free);
979
980 browser_load_dir (browser);
1238 g_mutex_lock (&sysex_transfer.mutex);
1239 sysex_transfer.active = TRUE;
1240 g_mutex_unlock (&sysex_transfer.mutex);
1241
1242 debug_print (1, "Creating SysEx thread...\n");
1243 sysex_thread = g_thread_new ("sysex_thread",
1244 elektroid_delete_files_runner, data);
1245 gtk_window_set_title (GTK_WINDOW (progress_dialog), _("Deleting Files"));
1246 gtk_label_set_text (GTK_LABEL (progress_label), _("Deleting..."));
1247 gtk_dialog_run (GTK_DIALOG (progress_dialog));
1248 gtk_widget_hide (GTK_WIDGET (progress_dialog));
1249
1250 elektroid_join_sysex_thread ();
1251
1252 g_mutex_lock (&sysex_transfer.mutex);
1253 sysex_transfer.active = FALSE;
1254 g_mutex_unlock (&sysex_transfer.mutex);
9811255 }
9821256
9831257 static void
9881262 int result;
9891263 gint err;
9901264 GtkTreeIter iter;
991 struct item *item;
1265 struct item item;
9921266 struct browser *browser = data;
9931267 GtkTreeModel *model =
9941268 GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view));
9951269
9961270 browser_set_selected_row_iter (browser, &iter);
997 item = browser_get_item (model, &iter);
998 old_path = browser_get_item_id_path (browser, item);
999
1000 gtk_entry_set_text (name_dialog_entry, item->name);
1271 browser_set_item (model, &iter, &item);
1272 old_path = browser_get_item_id_path (browser, &item);
1273
1274 gtk_entry_set_text (name_dialog_entry, item.name);
1275 gtk_entry_set_max_length (name_dialog_entry, browser->fs_ops->max_name_len);
10011276 gtk_widget_grab_focus (GTK_WIDGET (name_dialog_entry));
10021277 gtk_widget_set_sensitive (name_dialog_accept_button, FALSE);
10031278
10121287
10131288 if (result == GTK_RESPONSE_ACCEPT)
10141289 {
1015 new_path =
1016 chain_path (browser->dir, gtk_entry_get_text (name_dialog_entry));
1017
1018 err = browser->fs_ops->move (old_path, new_path, &connector);
1019
1290 if (browser->fs_ops->options & FS_OPTION_SLOT_STORAGE)
1291 {
1292 new_path = strdup (gtk_entry_get_text (name_dialog_entry));
1293 }
1294 else
1295 {
1296 new_path = chain_path (browser->dir,
1297 gtk_entry_get_text (name_dialog_entry));
1298 }
1299 err = browser->fs_ops->rename (&backend, old_path, new_path);
10201300 if (err)
10211301 {
10221302 show_error_msg (_("Error while renaming to “%s”: %s."),
1023 new_path, g_strerror (err));
1303 new_path, g_strerror (-err));
10241304 }
10251305 else
10261306 {
1027 browser_load_dir (browser);
1307 elektroid_load_remote_if_midi (browser);
10281308 }
1029
10301309 free (new_path);
10311310 }
10321311 }
10331312
1034 browser_free_item (item);
10351313 g_free (old_path);
10361314 gtk_widget_hide (GTK_WIDGET (name_dialog));
10371315 }
10381316
10391317 static gboolean
1040 elektroid_drag_begin (GtkWidget * widget,
1041 GdkDragContext * context, gpointer data)
1318 elektroid_drag_begin (GtkWidget * widget, GdkDragContext * context,
1319 gpointer data)
10421320 {
10431321 GtkTreeIter iter;
10441322 GtkTreeSelection *selection;
10451323 GtkTreeModel *model;
10461324 GList *tree_path_list;
10471325 GList *list;
1048 gchar *uri;
1326 gchar *uri, *escaped_uri;
10491327 gchar *path;
1050 struct item *item;
1328 struct item item;
10511329 struct browser *browser = data;
10521330
10531331 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
10581336 for (list = tree_path_list; list != NULL; list = g_list_next (list))
10591337 {
10601338 gtk_tree_model_get_iter (model, &iter, list->data);
1061 item = browser_get_item (model, &iter);
1062 path = browser_get_item_id_path (browser, item);
1063 browser_free_item (item);
1064 if (widget == GTK_WIDGET (local_browser.view))
1065 {
1066 uri = g_filename_to_uri (path, NULL, NULL);
1067 }
1068 else if (widget == GTK_WIDGET (remote_browser.view))
1339 browser_set_item (model, &iter, &item);
1340 path = browser_get_item_id_path (browser, &item);
1341 if (widget == GTK_WIDGET (local_browser.view) ||
1342 (widget == GTK_WIDGET (remote_browser.view)
1343 && backend.type == BE_TYPE_SYSTEM))
1344 {
1345 escaped_uri = g_filename_to_uri (path, NULL, NULL);
1346 }
1347 else
10691348 {
10701349 uri = chain_path ("file://", &path[1]);
1071 }
1072 else
1073 {
1074 continue;
1350 escaped_uri = g_uri_escape_string (uri, ":/", FALSE);
1351 g_free (uri);
10751352 }
10761353 g_free (path);
1077 g_string_append (browser->dnd_data, uri);
1078 g_free (uri);
1354 g_string_append (browser->dnd_data, escaped_uri);
1355 g_free (escaped_uri);
10791356 g_string_append (browser->dnd_data, "\n");
10801357 }
10811358 g_list_free_full (tree_path_list, (GDestroyNotify) gtk_tree_path_free);
11201397 return FALSE;
11211398 }
11221399
1400 static void
1401 elektroid_button_press_update_menu (struct browser *browser,
1402 GtkTreeSelection * selection,
1403 GtkTreePath * path)
1404 {
1405 if (gtk_tree_selection_path_is_selected (selection, path))
1406 {
1407 if (browser_get_selected_items_count (browser) == 1 &&
1408 !PLAYER_SOURCE_IS_BROWSER (browser))
1409 {
1410 browser->check_selection (NULL);
1411 }
1412 }
1413 else
1414 {
1415 gtk_tree_selection_unselect_all (selection);
1416 gtk_tree_selection_select_path (selection, path);
1417 }
1418 }
1419
11231420 static gboolean
11241421 elektroid_button_press (GtkWidget * treeview, GdkEventButton * event,
11251422 gpointer data)
11491446 return FALSE;
11501447 }
11511448
1152 if (!gtk_tree_selection_path_is_selected (selection, path))
1153 {
1154 gtk_tree_selection_unselect_all (selection);
1155 gtk_tree_selection_select_path (selection, path);
1156 }
1449 elektroid_button_press_update_menu (browser, selection, path);
1450
11571451 gtk_tree_path_free (path);
11581452 gtk_tree_selection_set_select_function (selection,
11591453 elektroid_selection_function_false,
11731467 return FALSE;
11741468 }
11751469
1176 if (!gtk_tree_selection_path_is_selected (selection, path))
1177 {
1178 gtk_tree_selection_unselect_all (selection);
1179 gtk_tree_selection_select_path (selection, path);
1180 }
1470 elektroid_button_press_update_menu (browser, selection, path);
1471
11811472 gtk_tree_path_free (path);
11821473 gtk_menu_popup_at_pointer (browser->menu, (GdkEvent *) event);
11831474
12391530 }
12401531
12411532 static void
1242 elektroid_redraw_sample (gdouble percent)
1533 elektroid_redraw_sample (struct job_control *control)
12431534 {
12441535 g_idle_add (elektroid_queue_draw_waveform, NULL);
12451536 }
12461537
12471538 static gpointer
1248 elektroid_load_sample (gpointer path)
1249 {
1250 struct sample_loop_data *sample_loop_data;
1539 elektroid_load_sample (gpointer data)
1540 {
1541 struct sample_params sample_params;
1542 struct sample_info *sample_info = audio.control.data;
1543
1544 sample_params.samplerate = AUDIO_SAMPLE_RATE;
1545 sample_params.channels = PLAYER_PREF_CHANNELS;
1546
1547 g_timeout_add (100, elektroid_update_ui_on_load, NULL);
1548
12511549 g_mutex_lock (&audio.control.mutex);
12521550 audio.control.active = TRUE;
12531551 g_mutex_unlock (&audio.control.mutex);
12541552
1255 if (sample_load_with_frames
1256 (path, audio.sample, &audio.control, &audio.frames) >= 0)
1257 {
1258 sample_loop_data = (struct sample_loop_data *) audio.control.data;
1259 debug_print (1, "Loop start at %d, loop end at %d\n",
1260 sample_loop_data->start, sample_loop_data->end);
1261 g_free (audio.control.data);
1553 if (sample_load_from_file (audio.path, audio.sample, &audio.control,
1554 &sample_params, &audio.frames) >= 0)
1555 {
1556 debug_print (1,
1557 "Samples: %d (%d B); channels: %d; loop start at %d; loop end at %d; sample rate: %.2f kHz; bit depth: %d\n",
1558 audio.frames, audio.sample->len, sample_info->channels,
1559 sample_info->loopstart, sample_info->loopend,
1560 sample_info->samplerate / 1000.0, sample_info->bitdepth);
12621561 }
12631562
12641563 g_mutex_lock (&audio.control.mutex);
12651564 audio.control.active = FALSE;
12661565 g_mutex_unlock (&audio.control.mutex);
12671566
1268 free (path);
1269
12701567 return NULL;
12711568 }
12721569
12731570 static void
1274 elektroid_start_load_thread (gchar * path)
1571 elektroid_start_load_thread ()
12751572 {
12761573 debug_print (1, "Creating load thread...\n");
1277
1278 load_thread = g_thread_new ("load_sample", elektroid_load_sample, path);
1279
1280 g_timeout_add (100, elektroid_update_ui_on_load, NULL);
1574 load_thread = g_thread_new ("load_sample", elektroid_load_sample, NULL);
12811575 }
12821576
12831577 static void
13191613 elektroid_join_task_thread ();
13201614 }
13211615
1322 static gboolean
1323 elektroid_remote_check_selection (gpointer data)
1324 {
1325 gint count = browser_get_selected_items_count (&remote_browser);
1326 gboolean dl_impl = remote_browser.fs_ops->download ? TRUE : FALSE;
1327 gboolean move_impl = remote_browser.fs_ops->move ? TRUE : FALSE;
1328 gboolean del_impl = remote_browser.fs_ops->delete ? TRUE : FALSE;
1329
1330 gtk_widget_set_sensitive (download_menuitem, count > 0 && dl_impl);
1331 gtk_widget_set_sensitive (remote_rename_menuitem, count == 1 && move_impl);
1332 gtk_widget_set_sensitive (remote_delete_menuitem, count > 0 && del_impl);
1333
1334 return FALSE;
1335 }
1336
1337 static gboolean
1338 elektroid_local_check_selection (gpointer data)
1339 {
1340 GtkTreeIter iter;
1341 gchar *sample_path;
1342 GtkTreeModel *model;
1343 gboolean audio_controls;
1344 struct item *item = NULL;
1345 gint count = browser_get_selected_items_count (&local_browser);
1346
1347 if (count == 0)
1348 {
1349 audio.name[0] = 0;
1350 }
1351 else if (count == 1)
1352 {
1353 browser_set_selected_row_iter (&local_browser, &iter);
1354 model = GTK_TREE_MODEL (gtk_tree_view_get_model (local_browser.view));
1355 item = browser_get_item (model, &iter);
1356 if (!strcmp (audio.name, item->name))
1357 {
1358 goto end;
1359 }
1360 }
1361
1362 if (!remote_browser.fs_ops || remote_browser.fs_ops->fs == FS_SAMPLES)
1616 static void
1617 elektroid_audio_widgets_set_status ()
1618 {
1619 gtk_widget_set_sensitive (local_open_menuitem, FALSE);
1620 gtk_widget_set_sensitive (remote_open_menuitem, FALSE);
1621 gtk_widget_set_sensitive (local_play_menuitem, FALSE);
1622 gtk_widget_set_sensitive (remote_play_menuitem, FALSE);
1623 gtk_widget_set_sensitive (play_button, FALSE);
1624 gtk_widget_set_sensitive (stop_button, FALSE);
1625 gtk_widget_set_visible (sample_info_box, FALSE);
1626 }
1627
1628 static void
1629 elektroid_reset_sample (struct browser *browser)
1630 {
1631 if (PLAYER_SOURCE_IS_BROWSER (browser))
13631632 {
13641633 audio_stop (&audio, TRUE);
13651634 elektroid_stop_load_thread ();
13661635 audio_reset_sample (&audio);
13671636 gtk_widget_queue_draw (waveform_draw_area);
1368
1369 if (item && item->type == ELEKTROID_FILE
1370 && strcmp (item->name, audio.name))
1371 {
1372 sample_path = chain_path (local_browser.dir, item->name);
1373 elektroid_start_load_thread (sample_path);
1374 strcpy (audio.name, item->name);
1375 }
1376
1377 }
1378
1379 end:
1380 audio_controls = item && item->type == ELEKTROID_FILE && (!remote_browser.fs_ops || remote_browser.fs_ops->fs == FS_SAMPLES); //1 sample file
1381 elektroid_sample_controls_set_sensitive (audio_controls);
1382 gtk_widget_set_sensitive (local_open_menuitem, audio_controls);
1383
1384 if (item)
1385 {
1386 browser_free_item (item);
1387 }
1637 elektroid_set_player_source (AUDIO_SRC_NONE);
1638 elektroid_audio_widgets_set_status ();
1639 }
1640 }
1641
1642 static void
1643 elektroid_check_and_load_sample (struct browser *browser, gint count)
1644 {
1645 struct item item;
1646 GtkTreeIter iter;
1647 gchar *sample_path;
1648 GtkTreeModel *model;
1649 gboolean audio_fs = !remote_browser.fs_ops
1650 || (remote_browser.fs_ops->options & FS_OPTION_AUDIO_PLAYER);
1651
1652 if (count == 1)
1653 {
1654 browser_set_selected_row_iter (browser, &iter);
1655 model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view));
1656 browser_set_item (model, &iter, &item);
1657
1658 gtk_widget_set_sensitive (browser ==
1659 &local_browser ? local_open_menuitem :
1660 remote_open_menuitem,
1661 item.type == ELEKTROID_FILE);
1662
1663 if (item.type == ELEKTROID_DIR)
1664 {
1665 elektroid_reset_sample (browser);
1666 }
1667 else
1668 {
1669 sample_path = chain_path (browser->dir, item.name);
1670
1671 if (strcmp (audio.path, sample_path)
1672 || PLAYER_GET_SOURCE (browser) != audio.src)
1673 {
1674 if (audio_fs)
1675 {
1676 audio_stop (&audio, TRUE);
1677 elektroid_stop_load_thread ();
1678 audio_reset_sample (&audio);
1679 strcpy (audio.path, sample_path);
1680 audio.src = PLAYER_GET_SOURCE (browser);
1681 elektroid_set_player_source (PLAYER_GET_SOURCE (browser));
1682 elektroid_start_load_thread ();
1683 }
1684 }
1685 g_free (sample_path);
1686 }
1687 }
1688 else
1689 {
1690 elektroid_reset_sample (browser);
1691 }
1692 }
1693
1694 static gboolean
1695 elektroid_remote_check_selection (gpointer data)
1696 {
1697 gint count = browser_get_selected_items_count (&remote_browser);
1698 gboolean dl_impl = remote_browser.fs_ops
1699 && remote_browser.fs_ops->download ? TRUE : FALSE;
1700 gboolean ren_impl = remote_browser.fs_ops
1701 && remote_browser.fs_ops->rename ? TRUE : FALSE;
1702 gboolean del_impl = remote_browser.fs_ops
1703 && remote_browser.fs_ops->delete ? TRUE : FALSE;
1704
1705 if (backend.type == BE_TYPE_SYSTEM)
1706 {
1707 elektroid_check_and_load_sample (&remote_browser, count);
1708 }
1709
1710 gtk_widget_set_sensitive (remote_show_menuitem, count <= 1);
1711 gtk_widget_set_sensitive (remote_rename_menuitem, count == 1 && ren_impl);
1712 gtk_widget_set_sensitive (remote_delete_menuitem, count > 0 && del_impl);
1713 gtk_widget_set_sensitive (download_menuitem, count > 0 && dl_impl);
1714
1715 return FALSE;
1716 }
1717
1718 static gboolean
1719 elektroid_local_check_selection (gpointer data)
1720 {
1721 gint count = browser_get_selected_items_count (&local_browser);
1722
1723 elektroid_check_and_load_sample (&local_browser, count);
13881724
13891725 gtk_widget_set_sensitive (local_show_menuitem, count <= 1);
13901726 gtk_widget_set_sensitive (local_rename_menuitem, count == 1);
14021738 guint width, height;
14031739 GdkRGBA color;
14041740 GtkStyleContext *context;
1405 int i, x_widget, x_sample;
1406 double x_ratio, mid_y, value;
1741 gint x_widget, x_sample;
1742 double x_ratio, mid_y1, mid_y2, value;
14071743 short *sample;
1744 double y_scale = 1.0 / (double) SHRT_MIN;
1745 double x_scale = 1.0 / (double) MAX_DRAW_X;
1746 struct sample_info *sample_info = audio.control.data;
1747 gboolean stereo = PLAYER_LOADED_CHANNELS == 2;
14081748
14091749 g_mutex_lock (&audio.control.mutex);
14101750
14111751 context = gtk_widget_get_style_context (widget);
1412 width = gtk_widget_get_allocated_width (widget);
1413 height = gtk_widget_get_allocated_height (widget);
1414 mid_y = height / 2.0;
1752 width = gtk_widget_get_allocated_width (widget) - 2;
1753 height = gtk_widget_get_allocated_height (widget) - 2;
1754 y_scale *= height;
1755 if (stereo)
1756 {
1757 mid_y1 = height * 0.25;
1758 mid_y2 = height * 0.75;
1759 y_scale *= 0.25;
1760 }
1761 else
1762 {
1763 mid_y1 = height * 0.50;
1764 y_scale *= 0.5;
1765 }
14151766 gtk_render_background (context, cr, 0, 0, width, height);
14161767 gtk_style_context_get_color (context, gtk_style_context_get_state (context),
14171768 &color);
14191770
14201771 sample = (short *) audio.sample->data;
14211772 x_ratio = audio.frames / (double) MAX_DRAW_X;
1422 for (i = 0; i < MAX_DRAW_X; i++)
1423 {
1424 x_sample = i * x_ratio;
1773 for (gint i = 0; i < MAX_DRAW_X; i++)
1774 {
1775 x_sample = i * x_ratio * (stereo ? 2 : 1);
1776 x_widget = i * width * x_scale;
14251777 if (x_sample < audio.sample->len >> 1)
14261778 {
1427 x_widget = i * ((double) width) / MAX_DRAW_X;
1428 value = mid_y - mid_y * (sample[x_sample] / (float) SHRT_MIN);
1429 cairo_move_to (cr, x_widget, mid_y);
1779 value = mid_y1 - sample[x_sample] * y_scale;
1780 cairo_move_to (cr, x_widget, mid_y1);
14301781 cairo_line_to (cr, x_widget, value);
14311782 cairo_stroke (cr);
1783 if (stereo)
1784 {
1785 value = mid_y2 - sample[x_sample + 1] * y_scale;
1786 cairo_move_to (cr, x_widget, mid_y2);
1787 cairo_line_to (cr, x_widget, value);
1788 cairo_stroke (cr);
1789 }
14321790 }
14331791 }
14341792
14471805 GVariantBuilder builder;
14481806 GFile *file;
14491807 GDBusProxy *proxy;
1450 struct item *item;
1808 struct item item;
14511809 gchar *path = NULL;
14521810 gboolean done = FALSE;
1453 gint count = browser_get_selected_items_count (&local_browser);
1811 struct browser *browser = data;
1812 gint count = browser_get_selected_items_count (browser);
14541813
14551814 if (count == 0)
14561815 {
1457 path = chain_path (local_browser.dir, NULL);
1816 path = chain_path (browser->dir, NULL);
14581817 }
14591818 else if (count == 1)
14601819 {
1461 browser_set_selected_row_iter (&local_browser, &iter);
1462 model = GTK_TREE_MODEL (gtk_tree_view_get_model (local_browser.view));
1463 item = browser_get_item (model, &iter);
1464 path = chain_path (local_browser.dir, item->name);
1465 browser_free_item (item);
1820 browser_set_selected_row_iter (browser, &iter);
1821 model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view));
1822 browser_set_item (model, &iter, &item);
1823 path = chain_path (browser->dir, item.name);
14661824 }
14671825 else
14681826 {
14781836 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
14791837 |
14801838 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
1481 NULL,
1482 "org.freedesktop.FileManager1",
1839 NULL, "org.freedesktop.FileManager1",
14831840 "/org/freedesktop/FileManager1",
1484 "org.freedesktop.FileManager1",
1485 NULL, NULL);
1841 "org.freedesktop.FileManager1", NULL,
1842 NULL);
14861843 if (proxy)
14871844 {
14881845 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
15191876 gchar *path;
15201877 gchar *uri;
15211878 GFile *file;
1522 struct item *item;
1523
1524 browser_set_selected_row_iter (&local_browser, &iter);
1525 model = GTK_TREE_MODEL (gtk_tree_view_get_model (local_browser.view));
1526 item = browser_get_item (model, &iter);
1527 path = chain_path (local_browser.dir, item->name);
1528 browser_free_item (item);
1879 struct item item;
1880 struct browser *browser = data;
1881
1882 browser_set_selected_row_iter (browser, &iter);
1883 model = GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view));
1884 browser_set_item (model, &iter, &item);
1885 path = chain_path (browser->dir, item.name);
15291886
15301887 file = g_file_new_for_path (path);
15311888 g_free (path);
15611918 return FALSE;
15621919 }
15631920
1921 static gboolean
1922 elektroid_mix_clicked (GtkWidget * object, gboolean state, gpointer data)
1923 {
1924 gchar *path;
1925 enum audio_src audio_src = audio.src;
1926 preferences.mix = state;
1927 if (strlen (audio.path))
1928 {
1929 audio_stop (&audio, TRUE);
1930 elektroid_stop_load_thread ();
1931 path = strdup (audio.path);
1932 audio_reset_sample (&audio);
1933 strcpy (audio.path, path);
1934 g_free (path);
1935 audio.src = audio_src;
1936 elektroid_start_load_thread ();
1937 }
1938 return FALSE;
1939 }
1940
15641941 static void
15651942 elektroid_set_volume (GtkScaleButton * button, gdouble value, gpointer data)
15661943 {
15671944 audio_set_volume (&audio, value);
15681945 }
15691946
1947 static gboolean
1948 elektroid_set_volume_callback_bg (gpointer data)
1949 {
1950 gdouble *value = data;
1951 debug_print (1, "Setting volume to %f...\n", *value);
1952 g_signal_handler_block (volume_button, volume_changed_handler);
1953 gtk_scale_button_set_value (GTK_SCALE_BUTTON (volume_button), *value);
1954 g_signal_handler_unblock (volume_button, volume_changed_handler);
1955 g_free (data);
1956 return FALSE;
1957 }
1958
15701959 static void
15711960 elektroid_set_volume_callback (gdouble value)
15721961 {
1573 gtk_scale_button_set_value (GTK_SCALE_BUTTON (volume_button), value);
1962 gdouble *v = g_malloc (sizeof (gdouble));
1963 *v = value;
1964 g_idle_add (elektroid_set_volume_callback_bg, v);
15741965 }
15751966
15761967 static void
15821973 struct browser *browser = data;
15831974
15841975 gtk_entry_set_text (name_dialog_entry, "");
1976 gtk_entry_set_max_length (name_dialog_entry, browser->fs_ops->max_name_len);
15851977 gtk_widget_grab_focus (GTK_WIDGET (name_dialog_entry));
15861978 gtk_widget_set_sensitive (name_dialog_accept_button, FALSE);
15871979
15991991 pathname =
16001992 chain_path (browser->dir, gtk_entry_get_text (name_dialog_entry));
16011993
1602 err = browser->fs_ops->mkdir (pathname, &connector);
1994 err = browser->fs_ops->mkdir (&backend, pathname);
16031995
16041996 if (err)
16051997 {
16061998 show_error_msg (_("Error while creating dir “%s”: %s."),
1607 pathname, g_strerror (err));
1999 pathname, g_strerror (-err));
16082000 }
16092001 else
16102002 {
1611 browser_load_dir (browser);
2003 elektroid_load_remote_if_midi (browser);
16122004 }
16132005
16142006 free (pathname);
18822274
18832275 if (!transfer_active && found)
18842276 {
2277 if (remote_browser.fs_ops->options & FS_OPTION_SINGLE_OP)
2278 {
2279 gtk_widget_set_sensitive (remote_box, FALSE);
2280 gtk_widget_set_sensitive (upload_menuitem, FALSE);
2281 }
2282 gtk_widget_set_sensitive (rx_sysex_button, FALSE);
2283 gtk_widget_set_sensitive (tx_sysex_button, FALSE);
2284 gtk_widget_set_sensitive (os_upgrade_button, FALSE);
2285
18852286 gtk_list_store_set (task_list_store, &iter,
18862287 TASK_LIST_STORE_STATUS_FIELD, RUNNING,
18872288 TASK_LIST_STORE_STATUS_HUMAN_FIELD, status_human,
18912292 gtk_tree_view_set_cursor (GTK_TREE_VIEW (task_tree_view), path, NULL,
18922293 FALSE);
18932294 gtk_tree_path_free (path);
2295 transfer.status = RUNNING;
18942296 transfer.control.active = TRUE;
18952297 transfer.control.callback = elektroid_update_progress;
18962298 transfer.src = src;
18972299 transfer.dst = dst;
1898 transfer.fs_ops = connector_get_fs_operations (fs);
2300 transfer.fs_ops = backend_get_fs_operations (&backend, fs, NULL);
18992301 debug_print (1, "Running task type %d from %s to %s (%s)...\n", type,
19002302 transfer.src, transfer.dst, elektroid_get_fs_name (fs));
19012303
19142316 }
19152317 else
19162318 {
2319 gtk_widget_set_sensitive (remote_box, TRUE);
2320 gtk_widget_set_sensitive (upload_menuitem, TRUE);
19172321 gtk_widget_set_sensitive (rx_sysex_button, TRUE);
19182322 gtk_widget_set_sensitive (tx_sysex_button, TRUE);
1919 gtk_widget_set_sensitive (os_upgrade_button, TRUE);
2323 gtk_widget_set_sensitive (os_upgrade_button,
2324 backend.upgrade_os != NULL);
19202325 }
19212326
19222327 elektroid_check_task_buttons (NULL);
19272332 static gpointer
19282333 elektroid_upload_task (gpointer data)
19292334 {
1930 gchar *dst_path;
1931 gchar *dst_dir;
19322335 gint res;
19332336 GByteArray *array;
2337 gchar *dst_path, *dst_dir;
19342338
19352339 debug_print (1, "Local path: %s\n", transfer.src);
19362340 debug_print (1, "Remote path: %s\n", transfer.dst);
2341
2342 dst_path = strdup (transfer.dst);
2343 dst_dir = dirname (dst_path);
2344
2345 if (remote_browser.fs_ops->mkdir
2346 && remote_browser.fs_ops->mkdir (remote_browser.backend, dst_dir))
2347 {
2348 error_print ("Error while creating remote %s dir\n", dst_dir);
2349 transfer.status = COMPLETED_ERROR;
2350 goto end_nodir;
2351 }
19372352
19382353 array = g_byte_array_new ();
19392354
19482363 debug_print (1, "Writing from file %s (filesystem %s)...\n", transfer.src,
19492364 elektroid_get_fs_name (transfer.fs_ops->fs));
19502365
1951 res = transfer.fs_ops->upload (transfer.dst, array, &transfer.control,
1952 remote_browser.data);
2366 res = transfer.fs_ops->upload (remote_browser.backend, transfer.dst, array,
2367 &transfer.control);
19532368 g_free (transfer.control.data);
19542369 transfer.control.data = NULL;
1955 g_idle_add (elektroid_check_connector_bg, NULL);
2370 g_idle_add (elektroid_check_backend_bg, NULL);
19562371
19572372 if (res && transfer.control.active)
19582373 {
19752390
19762391 if (!res && transfer.fs_ops == remote_browser.fs_ops) //There is no need to refresh the local browser
19772392 {
1978 dst_path = strdup (transfer.dst);
1979 dst_dir = dirname (dst_path);
1980 if (strcmp (dst_dir, remote_browser.dir) == 0)
1981 {
1982 g_idle_add (browser_load_dir, &remote_browser);
1983 }
1984 g_free (dst_path);
2393 if (!strncmp (dst_dir, remote_browser.dir, strlen (remote_browser.dir)))
2394 {
2395 g_idle_add (elektroid_load_remote_if_midi, &remote_browser);
2396 }
19852397 }
19862398
19872399 end_cleanup:
19882400 g_byte_array_free (array, TRUE);
19892401 g_idle_add (elektroid_complete_running_task, NULL);
19902402 g_idle_add (elektroid_run_next_task, NULL);
1991
2403 end_nodir:
2404 g_free (dst_path);
19922405 return NULL;
19932406 }
19942407
19982411 {
19992412 const gchar *status_human = elektroid_get_human_task_status (QUEUED);
20002413 const gchar *type_human = elektroid_get_human_task_type (type);
2001 const gchar *icon = elektroid_get_inventory_icon_for_fs (remote_fs_id);
2002
2414 const gchar *icon =
2415 backend_get_fs_operations (&backend, remote_fs_id, NULL)->gui_icon;
20032416
20042417 gtk_list_store_insert_with_values (task_list_store, NULL, -1,
20052418 TASK_LIST_STORE_STATUS_FIELD, QUEUED,
20202433 }
20212434
20222435 static void
2023 elektroid_add_upload_task_path (const gchar * rel_path, const gchar * src_dir,
2436 elektroid_add_upload_task_path (const gchar * rel_path,
2437 const gchar * src_dir,
20242438 const gchar * dst_dir,
20252439 struct item_iterator *remote_dir_iter,
20262440 gint32 * next_idx)
20272441 {
20282442 gint32 children_next_idx;
2029 gchar *path;
2030 gchar *dst_abs_dir;
2031 gchar *upload_path;
2032 struct item_iterator iter;
2033 struct item_iterator children_remote_item_iterator;
2443 struct item_iterator iter, iter_copy;
2444 gchar *path, *dst_abs_dir, *upload_path;
20342445 gchar *dst_abs_path = chain_path (dst_dir, rel_path);
20352446 gchar *src_abs_path = chain_path (src_dir, rel_path);
20362447
2037 if (local_browser.fs_ops->readdir (&iter, src_abs_path, local_browser.data))
2448 //Check if the item is a dir. If error, it's not.
2449 if (local_browser.fs_ops->readdir (local_browser.backend, &iter,
2450 src_abs_path))
20382451 {
20392452 dst_abs_dir = dirname (dst_abs_path);
2040 upload_path =
2041 connector_get_upload_path (&connector, remote_dir_iter,
2042 remote_browser.fs_ops, dst_abs_dir,
2043 src_abs_path, next_idx);
2044 elektroid_add_task (UPLOAD, src_abs_path, upload_path,
2045 remote_browser.fs_ops->fs);
2046 goto cleanup_not_dir;
2047 }
2048
2049 if (remote_browser.fs_ops->mkdir)
2050 {
2051 if (remote_browser.fs_ops->mkdir (dst_abs_path, remote_browser.data))
2052 {
2053 error_print ("Error while creating remote %s dir\n", dst_abs_path);
2054 goto cleanup;
2055 }
2056
2057 if (!strchr (rel_path, '/'))
2058 {
2059 browser_load_dir (&remote_browser);
2060 }
2061 }
2062
2063 if (!remote_browser.fs_ops->readdir (&children_remote_item_iterator,
2064 dst_abs_path, remote_browser.data))
2065 {
2066 while (!next_item_iterator (&iter))
2067 {
2068 path = chain_path (rel_path, iter.item.name);
2069 elektroid_add_upload_task_path (path, src_dir, dst_dir,
2070 &children_remote_item_iterator,
2071 &children_next_idx);
2072 free (path);
2073 }
2074
2075 free_item_iterator (&children_remote_item_iterator);
2076 }
2077
2078
2453 upload_path = remote_browser.fs_ops->get_upload_path (&backend,
2454 remote_dir_iter,
2455 remote_browser.fs_ops,
2456 dst_abs_dir,
2457 src_abs_path,
2458 next_idx);
2459 if (file_matches_extensions (src_abs_path, local_browser.extensions))
2460 {
2461 elektroid_add_task (UPLOAD, src_abs_path, upload_path,
2462 remote_browser.fs_ops->fs);
2463 }
2464 g_free (upload_path);
2465 goto cleanup;
2466 }
2467
2468 if (!remote_browser.fs_ops->mkdir)
2469 { //No recursive case.
2470 goto cleanup;
2471 }
2472
2473 copy_item_iterator (&iter_copy, &iter, TRUE);
2474 while (!next_item_iterator (&iter))
2475 {
2476 path = chain_path (rel_path, iter.item.name);
2477 elektroid_add_upload_task_path (path, src_dir, dst_dir,
2478 &iter_copy, &children_next_idx);
2479 free (path);
2480 }
2481 free_item_iterator (&iter_copy);
2482
2483 free_item_iterator (&iter);
20792484 cleanup:
2080 free_item_iterator (&iter);
2081 cleanup_not_dir:
20822485 g_free (dst_abs_path);
20832486 g_free (src_abs_path);
20842487 }
20852488
2086 static void
2087 elektroid_add_upload_task (GtkTreeModel * model,
2088 GtkTreePath * path,
2089 GtkTreeIter * iter, gpointer userdata)
2090 {
2091 struct item *item = browser_get_item (model, iter);
2092 struct elektroid_add_upload_task_data *data = userdata;
2093 elektroid_add_upload_task_path (item->name, local_browser.dir,
2094 remote_browser.dir, &data->iter,
2095 &data->index);
2096 browser_free_item (item);
2097 }
2098
2099 static void
2100 elektroid_add_upload_tasks (GtkWidget * object, gpointer userdata)
2101 {
2102 gboolean queued;
2489 static gpointer
2490 elektroid_add_upload_tasks_runner (gpointer userdata)
2491 {
2492 gint32 next_idx;
21032493 GtkTreeIter iter;
2104 struct elektroid_add_upload_task_data data;
2494 GList *selected_rows;
2495 struct item_iterator item_iterator;
2496 gboolean queued_before, queued_after, active;
2497 GtkTreeModel *model;
2498 GtkTreeSelection *selection;
2499
2500 g_timeout_add (100, elektroid_update_basic_sysex_progress, NULL);
2501
2502 model = GTK_TREE_MODEL (gtk_tree_view_get_model (local_browser.view));
2503 selection =
2504 gtk_tree_view_get_selection (GTK_TREE_VIEW (local_browser.view));
2505
2506 queued_before = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL,
2507 NULL);
2508
2509 local_browser.fs_ops->readdir (local_browser.backend, &item_iterator,
2510 local_browser.dir);
2511 next_idx = 1;
2512 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
2513 while (selected_rows)
2514 {
2515 struct item item;
2516 GtkTreeIter path_iter;
2517 GtkTreePath *path = selected_rows->data;
2518
2519 gtk_tree_model_get_iter (model, &path_iter, path);
2520 browser_set_item (model, &path_iter, &item);
2521 elektroid_add_upload_task_path (item.name, local_browser.dir,
2522 remote_browser.dir, &item_iterator,
2523 &next_idx);
2524
2525 g_mutex_lock (&sysex_transfer.mutex);
2526 active = sysex_transfer.active;
2527 g_mutex_unlock (&sysex_transfer.mutex);
2528
2529 if (!active)
2530 {
2531 break;
2532 }
2533
2534 selected_rows = g_list_next (selected_rows);
2535 }
2536 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
2537 free_item_iterator (&item_iterator);
2538
2539 queued_after = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL,
2540 NULL);
2541 if (!queued_before && queued_after)
2542 {
2543 g_idle_add (elektroid_run_next_task, NULL);
2544 }
2545
2546 sleep (1); //See elektroid_dnd_received_runner
2547 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_ACCEPT);
2548 return NULL;
2549 }
2550
2551 static void
2552 elektroid_add_upload_tasks (GtkWidget * object, gpointer data)
2553 {
21052554 GtkTreeSelection *selection =
21062555 gtk_tree_view_get_selection (GTK_TREE_VIEW (local_browser.view));
21072556
21102559 return;
21112560 }
21122561
2113 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL, NULL);
2114
2115 data.index = 1;
2116 remote_browser.fs_ops->readdir (&data.iter, remote_browser.dir,
2117 remote_browser.data);
2118 gtk_tree_selection_selected_foreach (selection, elektroid_add_upload_task,
2119 &data);
2120 free_item_iterator (&data.iter);
2121
2122 gtk_widget_set_sensitive (rx_sysex_button, FALSE);
2123 gtk_widget_set_sensitive (tx_sysex_button, FALSE);
2124 gtk_widget_set_sensitive (os_upgrade_button, FALSE);
2125
2126 if (!queued)
2127 {
2128 elektroid_run_next_task (NULL);
2129 }
2562 g_mutex_lock (&sysex_transfer.mutex);
2563 sysex_transfer.active = TRUE;
2564 g_mutex_unlock (&sysex_transfer.mutex);
2565
2566 debug_print (1, "Creating SysEx thread...\n");
2567 sysex_thread = g_thread_new ("sysex_thread",
2568 elektroid_add_upload_tasks_runner, NULL);
2569 gtk_window_set_title (GTK_WINDOW (progress_dialog), _("Preparing Tasks"));
2570 gtk_label_set_text (GTK_LABEL (progress_label), _("Waiting..."));
2571 gtk_dialog_run (GTK_DIALOG (progress_dialog));
2572 gtk_widget_hide (GTK_WIDGET (progress_dialog));
2573
2574 elektroid_join_sysex_thread ();
2575
2576 g_mutex_lock (&sysex_transfer.mutex);
2577 sysex_transfer.active = FALSE;
2578 g_mutex_unlock (&sysex_transfer.mutex);
21302579 }
21312580
21322581 static gpointer
21342583 {
21352584 gint res;
21362585 GByteArray *array;
2137
2138 array = g_byte_array_new ();
2586 gchar *dst_path, *dst_dir;
21392587
21402588 debug_print (1, "Remote path: %s\n", transfer.src);
21412589 debug_print (1, "Local path: %s\n", transfer.dst);
21422590
2143 res =
2144 transfer.fs_ops->download (transfer.src, array,
2145 &transfer.control, remote_browser.data);
2146 g_idle_add (elektroid_check_connector_bg, NULL);
2591 dst_path = strdup (transfer.dst);
2592 dst_dir = dirname (dst_path);
2593
2594 if (local_browser.fs_ops->mkdir (local_browser.backend, dst_dir))
2595 {
2596 error_print ("Error while creating local %s dir\n", dst_dir);
2597 transfer.status = COMPLETED_ERROR;
2598 goto end_nodir;
2599 }
2600
2601 array = g_byte_array_new ();
2602
2603 res = transfer.fs_ops->download (remote_browser.backend,
2604 transfer.src, array, &transfer.control);
2605 g_idle_add (elektroid_check_backend_bg, NULL);
21472606
21482607 g_mutex_lock (&transfer.control.mutex);
21492608 if (res && transfer.control.active)
21802639 g_idle_add (elektroid_complete_running_task, NULL);
21812640 g_idle_add (elektroid_run_next_task, NULL);
21822641
2642 end_nodir:
2643 g_free (dst_path);
21832644 return NULL;
21842645 }
21852646
21902651 struct item_iterator *remote_dir_iter)
21912652 {
21922653 struct item_iterator iter, iter_copy;
2193 gchar *path, *id, *download_path, *dst_abs_dirc, *dst_abs_dir;
2654 gchar *path, *dst_abs_dir, *download_path, *filename;
21942655 gchar *src_abs_path = chain_path (src_dir, rel_path);
21952656 gchar *dst_abs_path = chain_path (dst_dir, rel_path);
21962657
2197 if (remote_browser.
2198 fs_ops->readdir (&iter, src_abs_path, remote_browser.data))
2199 {
2200 dst_abs_dirc = strdup (dst_abs_path);
2201 dst_abs_dir = dirname (dst_abs_dirc);
2202 download_path =
2203 connector_get_download_path (&connector, remote_dir_iter,
2204 remote_browser.fs_ops, dst_abs_dir,
2205 src_abs_path);
2206 elektroid_add_task (DOWNLOAD, src_abs_path, download_path,
2207 remote_browser.fs_ops->fs);
2208 g_free (dst_abs_dirc);
2658 //Check if the item is a dir. If error, it's not.
2659 if (remote_browser.fs_ops->readdir (remote_browser.backend, &iter,
2660 src_abs_path))
2661 {
2662 dst_abs_dir = dirname (dst_abs_path);
2663 download_path = remote_browser.fs_ops->get_download_path (&backend,
2664 remote_dir_iter,
2665 remote_browser.fs_ops,
2666 dst_abs_dir,
2667 src_abs_path);
2668 if (file_matches_extensions (src_abs_path, remote_browser.extensions))
2669 {
2670 elektroid_add_task (DOWNLOAD, src_abs_path, download_path,
2671 remote_browser.fs_ops->fs);
2672 }
22092673 g_free (download_path);
2210 goto cleanup_not_dir;
2211 }
2212
2213 if (local_browser.fs_ops->mkdir (dst_abs_path, NULL))
2214 {
2215 error_print ("Error while creating local %s dir\n", dst_abs_path);
22162674 goto cleanup;
22172675 }
22182676
22192677 copy_item_iterator (&iter_copy, &iter, TRUE);
22202678 while (!next_item_iterator (&iter))
22212679 {
2222 id = remote_browser.fs_ops->getid (&iter.item);
2223 path = chain_path (rel_path, id);
2680 filename = get_filename (remote_browser.fs_ops->options, &iter.item);
2681 path = chain_path (rel_path, filename);
22242682 elektroid_add_download_task_path (path, src_dir, dst_dir, &iter_copy);
22252683 g_free (path);
2226 g_free (id);
2684 g_free (filename);
22272685 }
22282686 free_item_iterator (&iter_copy);
22292687
2688 free_item_iterator (&iter);
22302689 cleanup:
2231 free_item_iterator (&iter);
2232 cleanup_not_dir:
22332690 free (dst_abs_path);
22342691 free (src_abs_path);
22352692 }
22362693
2237 static void
2238 elektroid_add_download_task (GtkTreeModel * model,
2239 GtkTreePath * path,
2240 GtkTreeIter * iter, gpointer data)
2241 {
2242 struct item *item = browser_get_item (model, iter);
2243 char *id = remote_browser.fs_ops->getid (item);
2244
2245 elektroid_add_download_task_path (id, remote_browser.dir,
2246 local_browser.dir, data);
2247 g_free (id);
2248 browser_free_item (item);
2694 static gpointer
2695 elektroid_add_download_tasks_runner (gpointer data)
2696 {
2697 GtkTreeIter iter;
2698 GList *selected_rows;
2699 struct item_iterator item_iterator;
2700 gboolean queued_before, queued_after, active;
2701 GtkTreeModel *model;
2702 GtkTreeSelection *selection;
2703
2704 g_timeout_add (100, elektroid_update_basic_sysex_progress, NULL);
2705
2706 model = GTK_TREE_MODEL (gtk_tree_view_get_model (remote_browser.view));
2707 selection =
2708 gtk_tree_view_get_selection (GTK_TREE_VIEW (remote_browser.view));
2709
2710 queued_before = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL,
2711 NULL);
2712
2713 backend_enable_cache (remote_browser.backend);
2714
2715 remote_browser.fs_ops->readdir (remote_browser.backend, &item_iterator,
2716 remote_browser.dir);
2717 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
2718 while (selected_rows)
2719 {
2720 gchar *filename;
2721 struct item item;
2722 GtkTreeIter path_iter;
2723 GtkTreePath *path = selected_rows->data;
2724
2725 gtk_tree_model_get_iter (model, &path_iter, path);
2726 browser_set_item (model, &path_iter, &item);
2727 filename = get_filename (remote_browser.fs_ops->options, &item);
2728 elektroid_add_download_task_path (filename, remote_browser.dir,
2729 local_browser.dir, &item_iterator);
2730 g_free (filename);
2731
2732 g_mutex_lock (&sysex_transfer.mutex);
2733 active = sysex_transfer.active;
2734 g_mutex_unlock (&sysex_transfer.mutex);
2735
2736 if (!active)
2737 {
2738 break;
2739 }
2740
2741 selected_rows = g_list_next (selected_rows);
2742 }
2743 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
2744 free_item_iterator (&item_iterator);
2745
2746 backend_disable_cache (remote_browser.backend);
2747
2748 queued_after = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL,
2749 NULL);
2750 if (!queued_before && queued_after)
2751 {
2752 g_idle_add (elektroid_run_next_task, NULL);
2753 }
2754
2755 sleep (1); //See elektroid_dnd_received_runner
2756 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_ACCEPT);
2757 return NULL;
22492758 }
22502759
22512760 static void
22522761 elektroid_add_download_tasks (GtkWidget * object, gpointer data)
22532762 {
2254 gboolean queued;
2255 GtkTreeIter iter;
2256 struct item_iterator item_iterator;
22572763 GtkTreeSelection *selection =
22582764 gtk_tree_view_get_selection (GTK_TREE_VIEW (remote_browser.view));
22592765
22622768 return;
22632769 }
22642770
2265 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL, NULL);
2266
2267 remote_browser.fs_ops->readdir (&item_iterator, remote_browser.dir,
2268 remote_browser.data);
2269 gtk_tree_selection_selected_foreach (selection, elektroid_add_download_task,
2270 &item_iterator);
2271 free_item_iterator (&item_iterator);
2272
2273 gtk_widget_set_sensitive (rx_sysex_button, FALSE);
2274 gtk_widget_set_sensitive (tx_sysex_button, FALSE);
2275 gtk_widget_set_sensitive (os_upgrade_button, FALSE);
2276
2277 if (!queued)
2278 {
2279 elektroid_run_next_task (NULL);
2280 }
2771 g_mutex_lock (&sysex_transfer.mutex);
2772 sysex_transfer.active = TRUE;
2773 g_mutex_unlock (&sysex_transfer.mutex);
2774
2775 debug_print (1, "Creating SysEx thread...\n");
2776 sysex_thread = g_thread_new ("sysex_thread",
2777 elektroid_add_download_tasks_runner, NULL);
2778 gtk_window_set_title (GTK_WINDOW (progress_dialog), _("Preparing Tasks"));
2779 gtk_label_set_text (GTK_LABEL (progress_label), _("Waiting..."));
2780 gtk_dialog_run (GTK_DIALOG (progress_dialog));
2781 gtk_widget_hide (GTK_WIDGET (progress_dialog));
2782
2783 elektroid_join_sysex_thread ();
2784
2785 g_mutex_lock (&sysex_transfer.mutex);
2786 sysex_transfer.active = FALSE;
2787 g_mutex_unlock (&sysex_transfer.mutex);
22812788 }
22822789
22832790 static gboolean
22842791 elektroid_set_progress_value (gpointer data)
22852792 {
22862793 GtkTreeIter iter;
2287 gdouble *value = data;
2794 gdouble progress;
22882795
22892796 if (elektroid_get_running_task (&iter))
22902797 {
2798 g_mutex_lock (&transfer.control.mutex);
2799 progress = transfer.control.progress;
2800 g_mutex_unlock (&transfer.control.mutex);
2801
22912802 gtk_list_store_set (task_list_store, &iter,
22922803 TASK_LIST_STORE_PROGRESS_FIELD,
2293 100.0 * (*value), -1);
2804 100.0 * progress, -1);
22942805 }
22952806
22962807 free (data);
22992810 }
23002811
23012812 static void
2302 elektroid_update_progress (gdouble progress)
2303 {
2304 gdouble *value = malloc (sizeof (gdouble));
2305 *value = progress;
2306 g_idle_add (elektroid_set_progress_value, value);
2813 elektroid_update_progress (struct job_control *control)
2814 {
2815 g_idle_add (elektroid_set_progress_value, NULL);
23072816 }
23082817
23092818 static gboolean
23722881 elektroid_remote_key_press (GtkWidget * widget, GdkEventKey * event,
23732882 gpointer data)
23742883 {
2375 if (event->type == GDK_KEY_PRESS)
2376 {
2377 if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_Left)
2378 {
2379 if (remote_browser.fs_ops->download)
2380 {
2381 struct connector *connector = remote_browser.data;
2382 connector_enable_dir_cache (connector);
2383 elektroid_add_download_tasks (NULL, NULL);
2384 connector_disable_dir_cache (connector);
2385 }
2386 return TRUE;
2387 }
2388 else
2389 {
2390 return elektroid_common_key_press (widget, event, data);
2391 }
2392 }
2393
2394 return FALSE;
2884 if (event->type != GDK_KEY_PRESS)
2885 {
2886 return FALSE;
2887 }
2888
2889 if (!(event->state & GDK_CONTROL_MASK) || event->keyval != GDK_KEY_Left)
2890 {
2891 return elektroid_common_key_press (widget, event, data);
2892 }
2893
2894 if (!remote_browser.fs_ops->download)
2895 {
2896 return FALSE;
2897 }
2898
2899 elektroid_add_download_tasks (NULL, NULL);
2900 return TRUE;
23952901 }
23962902
23972903 static gboolean
23982904 elektroid_local_key_press (GtkWidget * widget, GdkEventKey * event,
23992905 gpointer data)
24002906 {
2401 if (event->type == GDK_KEY_PRESS)
2402 {
2403 if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_Right)
2404 {
2405 if (remote_browser.fs_ops->upload)
2907 if (event->type != GDK_KEY_PRESS)
2908 {
2909 return FALSE;
2910 }
2911
2912 if (!(event->state & GDK_CONTROL_MASK) || event->keyval != GDK_KEY_Right)
2913 {
2914 return elektroid_common_key_press (widget, event, data);
2915 }
2916
2917 if (remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE)
2918 {
2919 //Slot mode needs a slot destination.
2920 return FALSE;
2921 }
2922
2923 if (!remote_browser.fs_ops->upload)
2924 {
2925 return FALSE;
2926 }
2927
2928 elektroid_add_upload_tasks (NULL, NULL);
2929 return TRUE;
2930 }
2931
2932 static void
2933 elektroid_set_fs (GtkWidget * object, gpointer data)
2934 {
2935 GtkTreeIter iter;
2936 GValue fsv = G_VALUE_INIT;
2937 gint fs;
2938
2939 if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (fs_combo), &iter))
2940 {
2941 *remote_browser.dir = 0;
2942 remote_browser.fs_ops = NULL;
2943 browser_reset (&remote_browser);
2944 elektroid_set_local_file_extensions (0);
2945 browser_update_fs_options (&remote_browser);
2946 browser_load_dir (&local_browser);
2947 return;
2948 }
2949
2950 gtk_tree_model_get_value (GTK_TREE_MODEL (fs_list_store),
2951 &iter, FS_LIST_STORE_ID_FIELD, &fsv);
2952 fs = g_value_get_uint (&fsv);
2953
2954 remote_browser.fs_ops = backend_get_fs_operations (&backend, fs, NULL);
2955 remote_browser.file_icon = remote_browser.fs_ops->gui_icon;
2956
2957 strcpy (remote_browser.dir,
2958 backend.type == BE_TYPE_SYSTEM ? local_browser.dir : "/");
2959
2960 gtk_widget_set_visible (remote_play_separator,
2961 backend.type == BE_TYPE_SYSTEM);
2962 gtk_widget_set_visible (remote_play_menuitem,
2963 backend.type == BE_TYPE_SYSTEM);
2964 gtk_widget_set_visible (remote_options_separator,
2965 backend.type == BE_TYPE_SYSTEM);
2966 gtk_widget_set_visible (remote_open_menuitem,
2967 backend.type == BE_TYPE_SYSTEM);
2968 gtk_widget_set_visible (remote_show_menuitem,
2969 backend.type == BE_TYPE_SYSTEM);
2970 gtk_widget_set_visible (remote_actions_separator,
2971 backend.type == BE_TYPE_SYSTEM
2972 || remote_browser.fs_ops->rename != NULL
2973 || remote_browser.fs_ops->delete != NULL);
2974 gtk_widget_set_visible (remote_rename_menuitem,
2975 remote_browser.fs_ops->rename != NULL);
2976 gtk_widget_set_visible (remote_delete_menuitem,
2977 remote_browser.fs_ops->delete != NULL);
2978 gtk_widget_set_visible (local_audio_box, PLAYER_VISIBLE);
2979
2980 gtk_tree_view_column_set_visible (remote_tree_view_id_column,
2981 remote_browser.fs_ops->options &
2982 FS_OPTION_SHOW_ID_COLUMN);
2983 gtk_tree_view_column_set_visible (remote_tree_view_slot_column,
2984 remote_browser.fs_ops->options &
2985 FS_OPTION_SHOW_SLOT_COLUMN);
2986 gtk_tree_view_column_set_visible (remote_tree_view_size_column,
2987 remote_browser.fs_ops->options &
2988 FS_OPTION_SHOW_SIZE_COLUMN);
2989
2990 if (remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE)
2991 {
2992 gtk_drag_source_set ((GtkWidget *) remote_browser.view,
2993 GDK_BUTTON1_MASK, TARGET_ENTRIES_REMOTE_SRC,
2994 G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_SRC),
2995 GDK_ACTION_COPY);
2996 gtk_drag_dest_set ((GtkWidget *) remote_browser.view,
2997 GTK_DEST_DEFAULT_ALL, TARGET_ENTRIES_REMOTE_DST_SLOT,
2998 G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_DST_SLOT),
2999 GDK_ACTION_COPY);
3000 }
3001 else
3002 {
3003 if (backend.type == BE_TYPE_SYSTEM)
3004 {
3005 gtk_drag_source_set ((GtkWidget *) remote_browser.view,
3006 GDK_BUTTON1_MASK,
3007 TARGET_ENTRIES_REMOTE_SYSTEM_SRC,
3008 G_N_ELEMENTS
3009 (TARGET_ENTRIES_REMOTE_SYSTEM_SRC),
3010 GDK_ACTION_MOVE);
3011 gtk_drag_dest_set ((GtkWidget *) remote_browser.view,
3012 GTK_DEST_DEFAULT_ALL,
3013 TARGET_ENTRIES_REMOTE_SYSTEM_DST,
3014 G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_SYSTEM_DST),
3015 GDK_ACTION_MOVE);
3016 }
3017 else
3018 {
3019 gtk_drag_source_set ((GtkWidget *) remote_browser.view,
3020 GDK_BUTTON1_MASK, TARGET_ENTRIES_REMOTE_SRC,
3021 G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_SRC),
3022 GDK_ACTION_COPY);
3023 gtk_drag_dest_set ((GtkWidget *) remote_browser.view,
3024 GTK_DEST_DEFAULT_ALL, TARGET_ENTRIES_REMOTE_DST,
3025 G_N_ELEMENTS (TARGET_ENTRIES_REMOTE_DST),
3026 GDK_ACTION_COPY);
3027 }
3028 }
3029
3030 if (PLAYER_VISIBLE)
3031 {
3032 audio_stop (&audio, TRUE);
3033 }
3034
3035 browser_set_options (&remote_browser);
3036
3037 elektroid_set_remote_file_extensions (fs);
3038 browser_update_fs_options (&remote_browser);
3039 local_browser.file_icon = remote_browser.file_icon;
3040 elektroid_set_local_file_extensions (fs);
3041
3042 browser_load_dir (&remote_browser);
3043 browser_load_dir (&local_browser);
3044 }
3045
3046 static gboolean
3047 elektroid_fill_fs_combo_bg (gpointer data)
3048 {
3049 const struct fs_operations *ops;
3050 gint fs, i;
3051
3052 gtk_list_store_clear (fs_list_store);
3053
3054 if (!backend.device_desc.filesystems)
3055 {
3056 elektroid_set_fs (NULL, NULL);
3057 return FALSE;
3058 }
3059
3060 for (fs = 1, i = 0; i < MAX_BACKEND_FSS; fs = fs << 1, i++)
3061 {
3062 if (backend.device_desc.filesystems & fs)
3063 {
3064 ops = backend_get_fs_operations (&backend, fs, NULL);
3065 if (ops->gui_name)
24063066 {
2407 elektroid_add_upload_tasks (NULL, NULL);
3067 gtk_list_store_insert_with_values (fs_list_store, NULL, -1,
3068 FS_LIST_STORE_ID_FIELD,
3069 fs,
3070 FS_LIST_STORE_ICON_FIELD,
3071 ops->gui_icon,
3072 FS_LIST_STORE_NAME_FIELD,
3073 elektroid_get_fs_name (fs),
3074 -1);
24083075 }
2409 return TRUE;
2410 }
2411 else
2412 {
2413 return elektroid_common_key_press (widget, event, data);
2414 }
2415 }
3076 }
3077 }
3078
3079 if (i)
3080 {
3081 debug_print (1, "Selecting first filesystem...\n");
3082 gtk_combo_box_set_active (GTK_COMBO_BOX (fs_combo), 0);
3083 }
3084 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_ACCEPT);
24163085
24173086 return FALSE;
24183087 }
24193088
2420 static void
2421 elektroid_set_fs (GtkWidget * object, gpointer data)
3089 static gpointer
3090 elektroid_set_device_thread (gpointer data)
3091 {
3092 gchar *id = data;
3093 g_timeout_add (100, elektroid_update_basic_sysex_progress, NULL);
3094 sysex_transfer.err = connector_init (&backend, id, NULL, &sysex_transfer);
3095
3096 // TODO: Until a better solution is found, this sleep is necessary.
3097 // The reason is that this thread might end before the dialog is showed, which leads to erratic dialog behaviour.
3098 // This wait has impact.
3099 sleep (1);
3100 gtk_dialog_response (GTK_DIALOG (progress_dialog),
3101 backend_check (&backend) ? GTK_RESPONSE_ACCEPT
3102 : GTK_RESPONSE_CANCEL);
3103 return NULL;
3104 }
3105
3106 static void
3107 elektroid_set_device (GtkWidget * object, gpointer data)
24223108 {
24233109 GtkTreeIter iter;
2424 GtkTreeSortable *sortable;
2425 GValue fsv = G_VALUE_INIT;
2426 enum connector_fs fs;
2427
2428 if (gtk_combo_box_get_active_iter (fs_combo, &iter) == TRUE)
2429 {
2430 gtk_tree_model_get_value (GTK_TREE_MODEL (fs_list_store),
2431 &iter, FS_LIST_STORE_ID_FIELD, &fsv);
2432 fs = g_value_get_uint (&fsv);
2433
2434 remote_browser.fs_ops = connector_get_fs_operations (fs);
2435 remote_browser.file_icon = elektroid_get_inventory_icon_for_fs (fs);
2436 strcpy (remote_browser.dir, "/");
2437 browser_load_dir (&remote_browser);
2438
2439 local_browser.file_icon = remote_browser.file_icon;
2440 elektroid_set_file_extensions_for_fs (&local_browser.extensions, fs);
2441 browser_load_dir (&local_browser);
2442
2443 gtk_widget_set_sensitive (remote_browser.up_button,
2444 remote_browser.fs_ops->readdir != NULL);
2445 gtk_widget_set_visible (remote_browser.add_dir_button,
2446 remote_browser.fs_ops->mkdir != NULL);
2447 gtk_widget_set_sensitive (remote_browser.refresh_button,
2448 remote_browser.fs_ops->readdir != NULL);
2449
2450 gtk_widget_set_visible (remote_rename_menuitem,
2451 remote_browser.fs_ops->rename != NULL);
2452 gtk_widget_set_visible (remote_delete_menuitem,
2453 remote_browser.fs_ops->delete != NULL);
2454 gtk_widget_set_visible (local_audio_box, fs == FS_SAMPLES);
2455 gtk_tree_view_column_set_visible (remote_tree_view_index_column,
2456 fs == FS_DATA_PRJ
2457 || fs == FS_DATA_SND);
2458
2459 if (fs != FS_SAMPLES)
2460 {
2461 audio_stop (&audio, TRUE);
2462 }
2463
2464 sortable =
2465 GTK_TREE_SORTABLE (gtk_tree_view_get_model (remote_browser.view));
2466
2467 if (fs == FS_SAMPLES || fs == FS_RAW_PRESETS)
2468 {
2469 gtk_tree_sortable_set_sort_func (sortable,
2470 BROWSER_LIST_STORE_NAME_FIELD,
2471 browser_sort_samples, NULL, NULL);
2472 gtk_tree_sortable_set_sort_column_id (sortable,
2473 BROWSER_LIST_STORE_NAME_FIELD,
2474 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
2475 }
2476 else if (fs == FS_DATA_PRJ || fs == FS_DATA_SND)
2477 {
2478 gtk_tree_sortable_set_sort_func (sortable,
2479 BROWSER_LIST_STORE_INDEX_FIELD,
2480 browser_sort_data, NULL, NULL);
2481 gtk_tree_sortable_set_sort_column_id (sortable,
2482 BROWSER_LIST_STORE_INDEX_FIELD,
2483 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
2484 }
2485 }
2486 }
2487
2488 static void
2489 elektroid_fill_fs_combo ()
2490 {
2491 gtk_list_store_clear (fs_list_store);
2492
2493 for (int fs = FS_SAMPLES, i = 0; fs <= FS_DATA_SND; fs = fs << 1, i++)
2494 {
2495 if (GUI_FSS & fs && connector.device_desc.filesystems & fs)
2496 {
2497 gtk_list_store_insert_with_values (fs_list_store, NULL, -1,
2498 FS_LIST_STORE_ID_FIELD,
2499 fs,
2500 FS_LIST_STORE_ICON_FIELD,
2501 ELEKTROID_FS_ICONS[i],
2502 FS_LIST_STORE_NAME_FIELD,
2503 elektroid_get_fs_name (fs), -1);
2504 }
2505 }
2506
2507 debug_print (1, "Selecting first filesystem...\n");
2508 gtk_combo_box_set_active (fs_combo, 0);
2509 }
2510
2511 static void
2512 elektroid_set_device (GtkWidget * object, gpointer data)
2513 {
2514 GtkTreeIter iter;
2515 GValue cardv = G_VALUE_INIT;
2516 guint card;
2517
2518 if (gtk_combo_box_get_active_iter (devices_combo, &iter) == TRUE)
2519 {
2520 if (connector_check (&connector))
2521 {
2522 connector_destroy (&connector);
2523 }
2524
2525 gtk_tree_model_get_value (GTK_TREE_MODEL (devices_list_store),
2526 &iter, DEVICES_LIST_STORE_CARD_FIELD, &cardv);
2527
2528 card = g_value_get_uint (&cardv);
2529
2530 if (connector_init (&connector, card, NULL) < 0)
2531 {
2532 error_print ("Error while connecting\n");
2533 }
2534
2535 if (elektroid_check_connector ())
2536 {
2537 elektroid_fill_fs_combo ();
2538 }
2539 }
2540 }
2541
2542 static void
2543 elektroid_dnd_received_local (const gchar * type_name, const gchar * dir,
2544 const gchar * name, const gchar * filename,
2545 struct item_iterator *remote_item_iterator)
3110 gchar *id, *name;
3111 gint dres;
3112
3113 sysex_transfer.active = TRUE;
3114
3115 elektroid_cancel_all_tasks_and_wait ();
3116
3117 if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (devices_combo), &iter))
3118 {
3119 return;
3120 }
3121
3122 if (backend_check (&backend))
3123 {
3124 backend_destroy (&backend);
3125 }
3126
3127 gtk_tree_model_get (GTK_TREE_MODEL (devices_list_store), &iter,
3128 DEVICES_LIST_STORE_ID_FIELD, &id,
3129 DEVICES_LIST_STORE_NAME_FIELD, &name, -1);
3130
3131 if (!strcmp (id, BE_SYSTEM_ID) && !backend_init (&backend, id)
3132 && !system_handshake (&backend))
3133 {
3134 debug_print (1, "System backend detected\n");
3135 elektroid_fill_fs_combo_bg (NULL);
3136 elektroid_check_backend_bg (NULL);
3137 g_free (id);
3138 g_free (name);
3139 return;
3140 }
3141
3142 debug_print (1, "Creating SysEx thread...\n");
3143 sysex_thread = g_thread_new ("sysex_thread", elektroid_set_device_thread,
3144 id);
3145
3146 gtk_window_set_title (GTK_WINDOW (progress_dialog),
3147 _("Connecting to Device"));
3148 gtk_label_set_text (GTK_LABEL (progress_label), _("Connecting..."));
3149 dres = gtk_dialog_run (GTK_DIALOG (progress_dialog));
3150 gtk_widget_hide (GTK_WIDGET (progress_dialog));
3151
3152 elektroid_join_sysex_thread ();
3153
3154 if (sysex_transfer.err && sysex_transfer.err != -ECANCELED)
3155 {
3156 error_print ("Error while connecting: %s\n",
3157 g_strerror (-sysex_transfer.err));
3158 show_error_msg (_("Device “%s” not recognized: %s"), name,
3159 g_strerror (-sysex_transfer.err));
3160 }
3161
3162 g_free (id);
3163 g_free (name);
3164
3165 elektroid_check_backend_bg (NULL);
3166 if (dres == GTK_RESPONSE_ACCEPT)
3167 {
3168 elektroid_fill_fs_combo_bg (NULL);
3169 }
3170 else
3171 {
3172 gtk_combo_box_set_active (GTK_COMBO_BOX (devices_combo), -1);
3173 }
3174 }
3175
3176 static void
3177 elektroid_dnd_received_system (const gchar * dir, const gchar * name,
3178 const gchar * filename,
3179 struct browser *browser)
25463180 {
25473181 gchar *dst_path;
25483182 gint res;
25493183
2550 if (strcmp (type_name, TEXT_URI_LIST_STD) == 0)
2551 {
2552 if (strcmp (dir, local_browser.dir))
2553 {
2554 dst_path = chain_path (local_browser.dir, name);
2555 res = local_browser.fs_ops->move (filename, dst_path, NULL);
2556 if (res)
2557 {
2558 show_error_msg (_
2559 ("Error while moving from “%s” to “%s”: %s."),
2560 filename, dst_path, g_strerror (res));
2561 }
2562 g_free (dst_path);
2563 }
2564 else
2565 {
2566 debug_print (1, MSG_WARN_SAME_SRC_DST);
2567 }
2568 }
2569 else if (strcmp (type_name, TEXT_URI_LIST_ELEKTROID) == 0)
2570 {
2571 elektroid_add_download_task_path (name, dir, local_browser.dir,
2572 remote_item_iterator);
2573 }
2574 }
2575
2576 static void
2577 elektroid_dnd_received_remote (const gchar * type_name, const gchar * dir,
2578 const gchar * name, const gchar * filename,
3184 if (strcmp (dir, browser->dir))
3185 {
3186 dst_path = chain_path (browser->dir, name);
3187 res = browser->fs_ops->move (browser->backend, filename, dst_path);
3188 if (res)
3189 {
3190 error_print ("Error while moving from “%s” to “%s”: %s.\n",
3191 filename, dst_path, g_strerror (-res));
3192 }
3193 g_free (dst_path);
3194 }
3195 else
3196 {
3197 debug_print (1, MSG_WARN_SAME_SRC_DST);
3198 }
3199 }
3200
3201 static void
3202 elektroid_dnd_received_remote (const gchar * dir, const gchar * name,
3203 const gchar * filename,
25793204 struct item_iterator *remote_item_iterator,
25803205 gint32 * next_idx)
25813206 {
25823207 gchar *dst_path;
25833208 gint res;
25843209
2585 if (strcmp (type_name, TEXT_URI_LIST_ELEKTROID) == 0)
2586 {
2587 if (strcmp (dir, remote_browser.dir))
2588 {
2589 dst_path =
2590 connector_get_upload_path (&connector,
2591 remote_item_iterator,
2592 remote_browser.fs_ops,
2593 remote_browser.dir, name, next_idx);
2594 res =
2595 remote_browser.fs_ops->move (filename, dst_path,
2596 remote_browser.data);
2597 if (res)
3210 if (strcmp (dir, remote_browser.dir))
3211 {
3212 dst_path = remote_browser.fs_ops->get_upload_path (&backend,
3213 remote_item_iterator,
3214 remote_browser.fs_ops,
3215 remote_browser.dir,
3216 name, next_idx);
3217
3218 res = remote_browser.fs_ops->move (remote_browser.backend, filename,
3219 dst_path);
3220 if (res)
3221 {
3222 error_print ("Error while moving from “%s” to “%s”: %s.\n",
3223 filename, dst_path, g_strerror (-res));
3224 }
3225 g_free (dst_path);
3226 g_idle_add (elektroid_load_remote_if_midi, &remote_browser);
3227 }
3228 else
3229 {
3230 debug_print (1, MSG_WARN_SAME_SRC_DST);
3231 }
3232 }
3233
3234 static void
3235 elektroid_add_upload_task_slot (const gchar * name,
3236 const gchar * src_file_path, gint slot)
3237 {
3238 GtkTreeIter iter;
3239 GtkTreeModel *model;
3240 struct item item;
3241 gchar *dst_file_path, *name_wo_ext, *filename;
3242
3243 model =
3244 GTK_TREE_MODEL (gtk_tree_view_get_model
3245 (GTK_TREE_VIEW (remote_browser.view)));
3246
3247 if (gtk_tree_model_get_iter (model, &iter, remote_browser.dnd_motion_path))
3248 {
3249 for (gint i = 0; i < slot; i++)
3250 {
3251 if (!gtk_tree_model_iter_next (model, &iter))
25983252 {
2599 show_error_msg (_
2600 ("Error while moving from “%s” to “%s”: %s."),
2601 filename, dst_path, g_strerror (res));
3253 return;
26023254 }
2603 g_free (dst_path);
2604 browser_load_dir (&remote_browser);
2605 }
2606 else
2607 {
2608 debug_print (1, MSG_WARN_SAME_SRC_DST);
2609 }
2610 }
2611 else if (strcmp (type_name, TEXT_URI_LIST_STD) == 0)
2612 {
2613 elektroid_add_upload_task_path (name, dir, remote_browser.dir,
2614 remote_item_iterator, next_idx);
2615 }
3255 }
3256
3257 browser_set_item (model, &iter, &item);
3258
3259 filename = get_filename (remote_browser.fs_ops->options, &item);
3260 name_wo_ext = strdup (name);
3261 remove_ext (name_wo_ext);
3262 dst_file_path = g_malloc (PATH_MAX);
3263 snprintf (dst_file_path, PATH_MAX, "%s%s%s%s%s", remote_browser.dir,
3264 strcmp (remote_browser.dir, "/") ? "/" : "", filename,
3265 BE_SAMPLE_ID_NAME_SEPARATOR, name_wo_ext);
3266 g_free (name_wo_ext);
3267 g_free (filename);
3268
3269 elektroid_add_task (UPLOAD, src_file_path, dst_file_path,
3270 remote_browser.fs_ops->fs);
3271 }
3272 }
3273
3274 static gpointer
3275 elektroid_dnd_received_runner_dialog (gpointer data, gboolean dialog)
3276 {
3277 GtkWidget *widget = data;
3278 gint32 next_idx = 1;
3279 GtkTreeIter iter;
3280 struct item_iterator remote_item_iterator;
3281 gboolean queued_before, queued_after, load_remote, active;
3282
3283 if (dialog)
3284 {
3285 g_timeout_add (100, elektroid_update_basic_sysex_progress, NULL);
3286 }
3287
3288 queued_before = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL,
3289 NULL);
3290
3291 if (widget == GTK_WIDGET (local_browser.view))
3292 {
3293 backend_enable_cache (&backend);
3294 }
3295
3296 load_remote = widget == GTK_WIDGET (remote_browser.view) ||
3297 strcmp (dnd_type_name, TEXT_URI_LIST_ELEKTROID) == 0;
3298
3299 if (load_remote)
3300 {
3301 remote_browser.fs_ops->readdir (remote_browser.backend,
3302 &remote_item_iterator,
3303 remote_browser.dir);
3304 }
3305
3306 for (gint i = 0; dnd_uris[i] != NULL; i++)
3307 {
3308 g_mutex_lock (&sysex_transfer.mutex);
3309 active = sysex_transfer.active;
3310 g_mutex_unlock (&sysex_transfer.mutex);
3311
3312 if (!active)
3313 {
3314 goto end;
3315 }
3316
3317 gchar *filename = g_filename_from_uri (dnd_uris[i], NULL, NULL);
3318 gchar *path_basename = strdup (filename);
3319 gchar *path_dirname = strdup (filename);
3320 gchar *name = basename (path_basename);
3321 gchar *dir = dirname (path_dirname);
3322
3323 if (widget == GTK_WIDGET (local_browser.view))
3324 {
3325 if (strcmp (dnd_type_name, TEXT_URI_LIST_STD) == 0)
3326 {
3327 elektroid_dnd_received_system (dir, name, filename,
3328 &local_browser);
3329 }
3330 else if (strcmp (dnd_type_name, TEXT_URI_LIST_ELEKTROID) == 0)
3331 {
3332 elektroid_add_download_task_path (name, dir, local_browser.dir,
3333 &remote_item_iterator);
3334 }
3335 }
3336 else if (widget == GTK_WIDGET (remote_browser.view))
3337 {
3338 if (strcmp (dnd_type_name, TEXT_URI_LIST_ELEKTROID) == 0)
3339 {
3340 elektroid_dnd_received_remote (dir, name, filename,
3341 &remote_item_iterator,
3342 &next_idx);
3343 }
3344 else if (strcmp (dnd_type_name, TEXT_URI_LIST_STD) == 0)
3345 {
3346 if (remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE)
3347 {
3348 elektroid_add_upload_task_slot (name, filename, i);
3349 }
3350 else
3351 {
3352 if (backend.type == BE_TYPE_SYSTEM)
3353 {
3354 elektroid_dnd_received_system (dir, name, filename,
3355 &remote_browser);
3356 }
3357 else
3358 {
3359 elektroid_add_upload_task_path (name, dir,
3360 remote_browser.dir,
3361 &remote_item_iterator,
3362 &next_idx);
3363 }
3364 }
3365 }
3366 }
3367
3368 g_free (path_basename);
3369 g_free (path_dirname);
3370 g_free (filename);
3371 }
3372
3373 end:
3374 if (load_remote)
3375 {
3376 free_item_iterator (&remote_item_iterator);
3377 }
3378
3379 if (widget == GTK_WIDGET (local_browser.view))
3380 {
3381 backend_disable_cache (&backend);
3382 }
3383
3384 queued_after = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL,
3385 NULL);
3386 if (!queued_before && queued_after)
3387 {
3388 g_idle_add (elektroid_run_next_task, NULL);
3389 }
3390
3391 if (dialog)
3392 {
3393 // TODO: Until a better solution is found, this sleep is necessary.
3394 // The reason is that this thread might end before the dialog is showed, which leads to erratic dialog behaviour.
3395 // As we start to run the next task before sleeping, this has no impact.
3396 sleep (1);
3397 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_ACCEPT);
3398 }
3399 return NULL;
3400 }
3401
3402 static gpointer
3403 elektroid_dnd_received_runner (gpointer data)
3404 {
3405 return elektroid_dnd_received_runner_dialog (data, TRUE);
26163406 }
26173407
26183408 static void
26223412 guint info, guint time, gpointer userdata)
26233413 {
26243414 gchar *data;
2625 gchar **uris;
2626 gchar *filename;
2627 gchar *path_basename;
2628 gchar *path_dirname;
2629 gchar *name;
2630 gchar *dir;
2631 GtkTreeIter iter;
2632 gboolean queued;
26333415 GdkAtom type;
2634 gchar *type_name;
2635 gint32 next_idx = 1;
2636 struct item_iterator remote_item_iterator;
2637 struct connector *connector = remote_browser.data;
3416 gboolean background = TRUE;
26383417
26393418 if (selection_data == NULL
26403419 || !gtk_selection_data_get_length (selection_data)
26413420 || info != TARGET_STRING)
26423421 {
2643 goto end;
3422 gtk_drag_finish (context, TRUE, TRUE, time);
3423 return;
26443424 }
26453425
26463426 type = gtk_selection_data_get_data_type (selection_data);
2647 type_name = gdk_atom_name (type);
3427 dnd_type_name = gdk_atom_name (type);
26483428
26493429 data = (gchar *) gtk_selection_data_get_data (selection_data);
2650 debug_print (1, "DND received data (%s):\n%s\n", type_name, data);
2651
2652 uris = g_uri_list_extract_uris (data);
2653 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL, NULL);
2654
2655 if (widget == GTK_WIDGET (local_browser.view))
2656 {
2657 connector_enable_dir_cache (connector);
2658 }
2659
2660 remote_browser.fs_ops->readdir (&remote_item_iterator, remote_browser.dir,
2661 connector);
2662
2663 for (int i = 0; uris[i] != NULL; i++)
2664 {
2665 filename = g_filename_from_uri (uris[i], NULL, NULL);
2666 path_basename = strdup (filename);
2667 path_dirname = strdup (filename);
2668 name = basename (path_basename);
2669 dir = dirname (path_dirname);
2670
2671 if (widget == GTK_WIDGET (local_browser.view))
2672 {
2673 elektroid_dnd_received_local (type_name, dir, name, filename,
2674 &remote_item_iterator);
2675 }
2676 else if (widget == GTK_WIDGET (remote_browser.view))
2677 {
2678 elektroid_dnd_received_remote (type_name, dir, name, filename,
2679 &remote_item_iterator, &next_idx);
2680 }
2681
2682 g_free (path_basename);
2683 g_free (path_dirname);
2684 g_free (filename);
2685 }
2686
2687 free_item_iterator (&remote_item_iterator);
2688
2689 if (widget == GTK_WIDGET (local_browser.view))
2690 {
2691 connector_disable_dir_cache (connector);
2692 }
2693
2694 if (!queued)
2695 {
2696 elektroid_run_next_task (NULL);
2697 }
2698
2699 g_strfreev (uris);
2700
2701 end:
3430 debug_print (1, "DND received data (%s):\n%s\n", dnd_type_name, data);
3431
3432 dnd_uris = g_uri_list_extract_uris (data);
3433
27023434 gtk_drag_finish (context, TRUE, TRUE, time);
3435
3436 g_mutex_lock (&sysex_transfer.mutex);
3437 sysex_transfer.active = TRUE;
3438 g_mutex_unlock (&sysex_transfer.mutex);
3439
3440 if ((widget == GTK_WIDGET (local_browser.view)
3441 && !strcmp (dnd_type_name, TEXT_URI_LIST_STD)) ||
3442 (widget == GTK_WIDGET (remote_browser.view)
3443 && !strcmp (dnd_type_name, TEXT_URI_LIST_ELEKTROID)) ||
3444 (widget == GTK_WIDGET (remote_browser.view)
3445 && !strcmp (dnd_type_name, TEXT_URI_LIST_STD)
3446 && backend.type == BE_TYPE_SYSTEM))
3447 {
3448 gtk_window_set_title (GTK_WINDOW (progress_dialog), _("Moving Files"));
3449 gtk_label_set_text (GTK_LABEL (progress_label), _("Moving..."));
3450 if (!strcmp (dnd_type_name, TEXT_URI_LIST_STD))
3451 {
3452 background = FALSE;
3453 }
3454 }
3455 else
3456 {
3457 gtk_window_set_title (GTK_WINDOW (progress_dialog),
3458 _("Preparing Tasks"));
3459 gtk_label_set_text (GTK_LABEL (progress_label), _("Waiting..."));
3460 }
3461
3462 if (background)
3463 {
3464 debug_print (1, "Creating SysEx thread...\n");
3465 sysex_thread =
3466 g_thread_new ("sysex_thread", elektroid_dnd_received_runner, widget);
3467
3468 gtk_dialog_run (GTK_DIALOG (progress_dialog));
3469 gtk_widget_hide (GTK_WIDGET (progress_dialog));
3470
3471 g_mutex_lock (&sysex_transfer.mutex);
3472 sysex_transfer.active = FALSE;
3473 g_mutex_unlock (&sysex_transfer.mutex);
3474
3475 elektroid_join_sysex_thread ();
3476 }
3477 else
3478 {
3479 elektroid_dnd_received_runner_dialog (widget, FALSE);
3480 }
3481
3482 g_free (dnd_type_name);
3483 g_strfreev (dnd_uris);
27033484 }
27043485
27053486 static void
27643545 gchar *spath;
27653546 gint tx;
27663547 gint ty;
3548 gboolean slot;
27673549 GtkTreeSelection *selection;
2768 struct item *item;
3550 struct item item;
27693551 struct browser *browser = user_data;
3552
3553 slot = widget == GTK_WIDGET (remote_browser.view)
3554 && remote_browser.fs_ops->options & FS_OPTION_SLOT_STORAGE;
27703555
27713556 gtk_tree_view_convert_widget_to_bin_window_coords
27723557 (GTK_TREE_VIEW (widget), wx, wy, &tx, &ty);
27783563 debug_print (2, "Drag motion path: %s\n", spath);
27793564 g_free (spath);
27803565
2781 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view));
2782 if (gtk_tree_selection_path_is_selected (selection, path))
2783 {
2784 if (browser->dnd_timeout_function_id)
3566 if (slot)
3567 {
3568 gtk_tree_view_set_drag_dest_row (remote_browser.view, path,
3569 GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
3570 }
3571 else
3572 {
3573 selection =
3574 gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view));
3575 if (gtk_tree_selection_path_is_selected (selection, path))
27853576 {
2786 g_source_remove (browser->dnd_timeout_function_id);
2787 browser->dnd_timeout_function_id = 0;
3577 if (browser->dnd_timeout_function_id)
3578 {
3579 g_source_remove (browser->dnd_timeout_function_id);
3580 browser->dnd_timeout_function_id = 0;
3581 }
3582 return TRUE;
27883583 }
2789 return TRUE;
27903584 }
27913585
27923586 model =
27933587 GTK_TREE_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
27943588 gtk_tree_model_get_iter (model, &iter, path);
2795 item = browser_get_item (model, &iter);
2796
2797 if (item->type == ELEKTROID_DIR && (!browser->dnd_motion_path
2798 || (browser->dnd_motion_path
2799 &&
2800 gtk_tree_path_compare
2801 (browser->dnd_motion_path,
2802 path))))
3589 browser_set_item (model, &iter, &item);
3590
3591 if (item.type == ELEKTROID_DIR && (!browser->dnd_motion_path
3592 || (browser->dnd_motion_path
3593 &&
3594 gtk_tree_path_compare
3595 (browser->dnd_motion_path,
3596 path))))
28033597 {
28043598 if (browser->dnd_timeout_function_id)
28053599 {
28093603 browser->dnd_timeout_function_id =
28103604 g_timeout_add (DND_TIMEOUT, elektroid_drag_list_timeout, browser);
28113605 }
2812
2813 browser_free_item (item);
28143606 }
28153607 else
28163608 {
28193611 g_source_remove (browser->dnd_timeout_function_id);
28203612 browser->dnd_timeout_function_id = 0;
28213613 }
2822
28233614 }
28243615
28253616 if (browser->dnd_motion_path)
28273618 gtk_tree_path_free (browser->dnd_motion_path);
28283619 browser->dnd_motion_path = NULL;
28293620 }
2830
28313621 browser->dnd_motion_path = path;
28323622
28333623 return TRUE;
28883678 }
28893679
28903680 static void
2891 elektroid_notify_local_dir_change (struct browser *browser)
2892 {
2893 notifier_set_dir (&notifier, browser->dir);
2894 }
2895
2896 static void
28973681 elektroid_quit ()
28983682 {
3683 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_CANCEL);
3684
28993685 elektroid_stop_sysex_thread ();
29003686 elektroid_stop_task_thread ();
29013687 elektroid_stop_load_thread ();
29023688
2903 notifier.running = 0;
2904 notifier_close (&notifier);
2905 g_thread_join (notifier_thread);
2906 notifier_free (&notifier);
3689 browser_destroy (&local_browser);
3690 browser_destroy (&remote_browser);
3691
3692 audio_destroy (&audio);
29073693
29083694 debug_print (1, "Quitting GTK+...\n");
29093695 gtk_main_quit ();
29213707 {
29223708 GtkBuilder *builder;
29233709 GtkCssProvider *css_provider;
2924 GtkTreeSortable *sortable;
29253710 GtkWidget *name_dialog_cancel_button;
29263711 GtkWidget *refresh_devices_button;
29273712 GtkWidget *hostname_label;
2928 GtkWidget *loop_button;
2929 GtkWidget *autoplay_switch;
2930 gchar *glade_file;
2931 gchar *css_file;
29323713 gchar hostname[LABEL_MAX];
2933
2934 glade_file = chain_path (DATADIR, "gui.glade");
2935 css_file = chain_path (DATADIR, "gui.css");
29363714
29373715 gtk_init (&argc, &argv);
29383716 builder = gtk_builder_new ();
2939 gtk_builder_add_from_file (builder, glade_file, NULL);
2940 free (glade_file);
3717 gtk_builder_add_from_file (builder, DATADIR "/gui.glade", NULL);
29413718
29423719 css_provider = gtk_css_provider_new ();
2943 gtk_css_provider_load_from_path (css_provider, css_file, NULL);
3720 gtk_css_provider_load_from_path (css_provider, DATADIR "/gui.css", NULL);
29443721 gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
29453722 GTK_STYLE_PROVIDER
29463723 (css_provider),
29473724 GTK_STYLE_PROVIDER_PRIORITY_USER);
2948 free (css_file);
29493725
29503726 main_window = GTK_WIDGET (gtk_builder_get_object (builder, "main_window"));
29513727 gtk_window_resize (GTK_WINDOW (main_window), 1, 1); //Compact window
29863762 hostname_label =
29873763 GTK_WIDGET (gtk_builder_get_object (builder, "hostname_label"));
29883764
3765 local_box = GTK_WIDGET (gtk_builder_get_object (builder, "local_box"));
29893766 remote_box = GTK_WIDGET (gtk_builder_get_object (builder, "remote_box"));
29903767 local_audio_box =
29913768 GTK_WIDGET (gtk_builder_get_object (builder, "local_audio_box"));
29963773 loop_button = GTK_WIDGET (gtk_builder_get_object (builder, "loop_button"));
29973774 autoplay_switch =
29983775 GTK_WIDGET (gtk_builder_get_object (builder, "autoplay_switch"));
3776 mix_switch = GTK_WIDGET (gtk_builder_get_object (builder, "mix_switch"));
29993777 volume_button =
30003778 GTK_WIDGET (gtk_builder_get_object (builder, "volume_button"));
30013779 status_bar = GTK_STATUSBAR (gtk_builder_get_object (builder, "status_bar"));
30043782 G_CALLBACK (elektroid_delete_window), NULL);
30053783
30063784 g_signal_connect (progress_dialog_cancel_button, "clicked",
3007 G_CALLBACK (elektroid_progress_dialog_end), NULL);
3785 G_CALLBACK (elektroid_progress_dialog_close), NULL);
30083786 g_signal_connect (progress_dialog, "response",
30093787 G_CALLBACK (elektroid_cancel_running_sysex), NULL);
30103788
30353813 G_CALLBACK (elektroid_loop_clicked), NULL);
30363814 g_signal_connect (autoplay_switch, "state-set",
30373815 G_CALLBACK (elektroid_autoplay_clicked), NULL);
3038 g_signal_connect (volume_button, "value_changed",
3039 G_CALLBACK (elektroid_set_volume), NULL);
3816 g_signal_connect (mix_switch, "state-set",
3817 G_CALLBACK (elektroid_mix_clicked), NULL);
3818 volume_changed_handler = g_signal_connect (volume_button, "value_changed",
3819 G_CALLBACK
3820 (elektroid_set_volume), NULL);
30403821
30413822 download_menuitem =
30423823 GTK_WIDGET (gtk_builder_get_object (builder, "download_menuitem"));
3824 remote_play_separator =
3825 GTK_WIDGET (gtk_builder_get_object (builder, "remote_play_separator"));
3826 remote_play_menuitem =
3827 GTK_WIDGET (gtk_builder_get_object (builder, "remote_play_menuitem"));
3828 remote_options_separator =
3829 GTK_WIDGET (gtk_builder_get_object (builder, "remote_options_separator"));
3830 remote_open_menuitem =
3831 GTK_WIDGET (gtk_builder_get_object (builder, "remote_open_menuitem"));
3832 remote_show_menuitem =
3833 GTK_WIDGET (gtk_builder_get_object (builder, "remote_show_menuitem"));
3834 remote_actions_separator =
3835 GTK_WIDGET (gtk_builder_get_object (builder, "remote_actions_separator"));
30433836 remote_rename_menuitem =
30443837 GTK_WIDGET (gtk_builder_get_object (builder, "remote_rename_menuitem"));
30453838 remote_delete_menuitem =
30463839 GTK_WIDGET (gtk_builder_get_object (builder, "remote_delete_menuitem"));
30473840 g_signal_connect (download_menuitem, "activate",
30483841 G_CALLBACK (elektroid_add_download_tasks), NULL);
3842 g_signal_connect (remote_play_menuitem, "activate",
3843 G_CALLBACK (elektroid_play_clicked), NULL);
3844 g_signal_connect (remote_open_menuitem, "activate",
3845 G_CALLBACK (elektroid_open_clicked), &remote_browser);
3846 g_signal_connect (remote_show_menuitem, "activate",
3847 G_CALLBACK (elektroid_show_clicked), &remote_browser);
30493848 g_signal_connect (remote_rename_menuitem, "activate",
30503849 G_CALLBACK (elektroid_rename_item), &remote_browser);
30513850 g_signal_connect (remote_delete_menuitem, "activate",
30533852
30543853 upload_menuitem =
30553854 GTK_WIDGET (gtk_builder_get_object (builder, "upload_menuitem"));
3855 local_play_separator =
3856 GTK_WIDGET (gtk_builder_get_object (builder, "local_play_separator"));
30563857 local_play_menuitem =
30573858 GTK_WIDGET (gtk_builder_get_object (builder, "local_play_menuitem"));
30583859 local_open_menuitem =
30683869 g_signal_connect (local_play_menuitem, "activate",
30693870 G_CALLBACK (elektroid_play_clicked), NULL);
30703871 g_signal_connect (local_open_menuitem, "activate",
3071 G_CALLBACK (elektroid_open_clicked), NULL);
3872 G_CALLBACK (elektroid_open_clicked), &local_browser);
30723873 g_signal_connect (local_show_menuitem, "activate",
3073 G_CALLBACK (elektroid_show_clicked), NULL);
3874 G_CALLBACK (elektroid_show_clicked), &local_browser);
30743875 g_signal_connect (local_rename_menuitem, "activate",
30753876 G_CALLBACK (elektroid_rename_item), &local_browser);
30763877 g_signal_connect (local_delete_menuitem, "activate",
30783879
30793880 remote_browser = (struct browser)
30803881 {
3882 .name = "remote",
30813883 .view =
30823884 GTK_TREE_VIEW (gtk_builder_get_object (builder, "remote_tree_view")),
30833885 .up_button =
30893891 .dir_entry =
30903892 GTK_ENTRY (gtk_builder_get_object (builder, "remote_dir_entry")),
30913893 .menu = GTK_MENU (gtk_builder_get_object (builder, "remote_menu")),
3092 .dir = malloc (PATH_MAX),
3894 .dir = g_malloc0 (PATH_MAX),
30933895 .check_selection = elektroid_remote_check_selection,
30943896 .file_icon = NULL,
3095 .fs_ops = connector_get_fs_operations (-1),
3096 .data = &connector,
3097 .notify_dir_change = NULL,
3098 .check_callback = elektroid_check_connector
3897 .fs_ops = NULL,
3898 .backend = &backend,
3899 .check_callback = elektroid_check_backend,
3900 .sensitive_widgets = NULL,
3901 .stack = GTK_WIDGET (gtk_builder_get_object (builder, "remote_stack")),
3902 .spinner = GTK_WIDGET (gtk_builder_get_object (builder, "remote_spinner"))
30993903 };
3100 remote_tree_view_index_column =
3904 browser_init (&remote_browser);
3905
3906 remote_tree_view_id_column =
31013907 GTK_TREE_VIEW_COLUMN (gtk_builder_get_object
3102 (builder, "remote_tree_view_index_column"));
3908 (builder, "remote_tree_view_id_column"));
3909 remote_tree_view_slot_column =
3910 GTK_TREE_VIEW_COLUMN (gtk_builder_get_object
3911 (builder, "remote_tree_view_slot_column"));
3912 remote_tree_view_size_column =
3913 GTK_TREE_VIEW_COLUMN (gtk_builder_get_object
3914 (builder, "remote_tree_view_size_column"));
31033915
31043916 g_signal_connect (gtk_tree_view_get_selection (remote_browser.view),
31053917 "changed", G_CALLBACK (browser_selection_changed),
31353947 g_signal_connect (remote_browser.up_button, "drag-leave",
31363948 G_CALLBACK (elektroid_drag_leave_up), &remote_browser);
31373949
3138 gtk_drag_source_set ((GtkWidget *) remote_browser.view, GDK_BUTTON1_MASK,
3139 TARGET_ENTRIES_REMOTE_SRC, TARGET_ENTRIES_REMOTE_SRC_N,
3140 GDK_ACTION_COPY);
3141 gtk_drag_dest_set ((GtkWidget *) remote_browser.view, GTK_DEST_DEFAULT_ALL,
3142 TARGET_ENTRIES_REMOTE_DST, TARGET_ENTRIES_REMOTE_DST_N,
3143 GDK_ACTION_COPY);
31443950 gtk_drag_dest_set ((GtkWidget *) remote_browser.up_button,
31453951 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT,
31463952 TARGET_ENTRIES_UP_BUTTON_DST,
3147 TARGET_ENTRIES_UP_BUTTON_DST_N, GDK_ACTION_COPY);
3953 G_N_ELEMENTS (TARGET_ENTRIES_UP_BUTTON_DST),
3954 GDK_ACTION_COPY);
31483955
31493956 local_browser = (struct browser)
31503957 {
3958 .name = "local",
31513959 .view =
31523960 GTK_TREE_VIEW (gtk_builder_get_object (builder, "local_tree_view")),
31533961 .up_button =
31593967 .dir_entry =
31603968 GTK_ENTRY (gtk_builder_get_object (builder, "local_dir_entry")),
31613969 .menu = GTK_MENU (gtk_builder_get_object (builder, "local_menu")),
3162 .dir = malloc (PATH_MAX),
3970 .dir = preferences.local_dir,
31633971 .check_selection = elektroid_local_check_selection,
3164 .file_icon = elektroid_get_inventory_icon_for_fs (FS_SAMPLES),
3972 .file_icon = BE_FILE_ICON_WAVE,
31653973 .extensions = NULL,
31663974 .fs_ops = &FS_LOCAL_OPERATIONS,
3167 .data = NULL,
3168 .notify_dir_change = elektroid_notify_local_dir_change,
3169 .check_callback = NULL
3975 .backend = NULL,
3976 .check_callback = NULL,
3977 .sensitive_widgets = NULL,
3978 .stack = GTK_WIDGET (gtk_builder_get_object (builder, "local_stack")),
3979 .spinner = GTK_WIDGET (gtk_builder_get_object (builder, "local_spinner"))
31703980 };
3981 browser_init (&local_browser);
31713982
31723983 g_signal_connect (gtk_tree_view_get_selection (local_browser.view),
31733984 "changed", G_CALLBACK (browser_selection_changed),
32034014 g_signal_connect (local_browser.up_button, "drag-leave",
32044015 G_CALLBACK (elektroid_drag_leave_up), &local_browser);
32054016
3206 sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (local_browser.view));
3207 gtk_tree_sortable_set_sort_func (sortable, BROWSER_LIST_STORE_NAME_FIELD,
3208 browser_sort_samples, NULL, NULL);
3209 gtk_tree_sortable_set_sort_column_id (sortable,
3210 BROWSER_LIST_STORE_NAME_FIELD,
3211 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
4017 browser_set_options (&local_browser);
32124018
32134019 gtk_drag_source_set ((GtkWidget *) local_browser.view, GDK_BUTTON1_MASK,
3214 TARGET_ENTRIES_LOCAL_SRC, TARGET_ENTRIES_LOCAL_SRC_N,
4020 TARGET_ENTRIES_LOCAL_SRC,
4021 G_N_ELEMENTS (TARGET_ENTRIES_LOCAL_SRC),
32154022 GDK_ACTION_MOVE);
32164023 gtk_drag_dest_set ((GtkWidget *) local_browser.view, GTK_DEST_DEFAULT_ALL,
3217 TARGET_ENTRIES_LOCAL_DST, TARGET_ENTRIES_LOCAL_DST_N,
4024 TARGET_ENTRIES_LOCAL_DST,
4025 G_N_ELEMENTS (TARGET_ENTRIES_LOCAL_DST),
32184026 GDK_ACTION_COPY);
32194027 gtk_drag_dest_set ((GtkWidget *) local_browser.up_button,
32204028 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT,
32214029 TARGET_ENTRIES_UP_BUTTON_DST,
3222 TARGET_ENTRIES_UP_BUTTON_DST_N, GDK_ACTION_COPY);
3223
3224 audio_init (&audio, elektroid_set_volume_callback, elektroid_redraw_sample);
4030 G_N_ELEMENTS (TARGET_ENTRIES_UP_BUTTON_DST),
4031 GDK_ACTION_COPY);
32254032
32264033 devices_list_store =
32274034 GTK_LIST_STORE (gtk_builder_get_object (builder, "devices_list_store"));
32284035 devices_combo =
3229 GTK_COMBO_BOX (gtk_builder_get_object (builder, "devices_combo"));
4036 GTK_WIDGET (gtk_builder_get_object (builder, "devices_combo"));
32304037 refresh_devices_button =
32314038 GTK_WIDGET (gtk_builder_get_object (builder, "refresh_devices_button"));
32324039 g_signal_connect (devices_combo, "changed",
32334040 G_CALLBACK (elektroid_set_device), NULL);
32344041 g_signal_connect (refresh_devices_button, "clicked",
3235 G_CALLBACK (browser_refresh_devices), NULL);
4042 G_CALLBACK (elektroid_refresh_devices), NULL);
4043
4044 audio_init (&audio, elektroid_set_volume_callback, elektroid_redraw_sample);
32364045
32374046 task_list_store =
32384047 GTK_LIST_STORE (gtk_builder_get_object (builder, "task_list_store"));
32554064 gtk_statusbar_push (status_bar, 0, _("Not connected"));
32564065 elektroid_loop_clicked (loop_button, NULL);
32574066 gtk_switch_set_active (GTK_SWITCH (autoplay_switch), preferences.autoplay);
4067 gtk_switch_set_active (GTK_SWITCH (mix_switch), preferences.mix);
32584068
32594069 fs_list_store =
32604070 GTK_LIST_STORE (gtk_builder_get_object (builder, "fs_list_store"));
3261 fs_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "fs_combo"));
4071 fs_combo = GTK_WIDGET (gtk_builder_get_object (builder, "fs_combo"));
32624072 g_signal_connect (fs_combo, "changed", G_CALLBACK (elektroid_set_fs), NULL);
4073
4074 sample_info_box =
4075 GTK_WIDGET (gtk_builder_get_object (builder, "sample_info_box"));
4076 sample_length =
4077 GTK_WIDGET (gtk_builder_get_object (builder, "sample_length"));
4078 sample_duration =
4079 GTK_WIDGET (gtk_builder_get_object (builder, "sample_duration"));
4080 sample_channels =
4081 GTK_WIDGET (gtk_builder_get_object (builder, "sample_channels"));
4082 sample_samplerate =
4083 GTK_WIDGET (gtk_builder_get_object (builder, "sample_samplerate"));
4084 sample_bitdepth =
4085 GTK_WIDGET (gtk_builder_get_object (builder, "sample_bitdepth"));
32634086
32644087 gtk_widget_set_sensitive (remote_box, FALSE);
32654088 gtk_widget_set_sensitive (rx_sysex_button, FALSE);
32664089 gtk_widget_set_sensitive (tx_sysex_button, FALSE);
32674090 gtk_widget_set_sensitive (os_upgrade_button, FALSE);
32684091
3269 local_browser.dir = preferences.local_dir;
3270 elektroid_load_devices (TRUE); //This triggers a local browser reload due to the extensions and icons selected for the fs
4092 elektroid_audio_widgets_set_status ();
32714093
32724094 gethostname (hostname, LABEL_MAX);
32734095 gtk_label_set_text (GTK_LABEL (hostname_label), hostname);
32744096
3275 debug_print (1, "Creating notifier thread...\n");
3276 notifier_init (&notifier, &local_browser);
3277 notifier_set_dir (&notifier, preferences.local_dir);
3278 notifier_thread = g_thread_new ("notifier_thread", notifier_run, &notifier);
3279
4097 local_browser.sensitive_widgets =
4098 g_slist_append (local_browser.sensitive_widgets, local_box);
4099 remote_browser.sensitive_widgets =
4100 g_slist_append (remote_browser.sensitive_widgets, devices_combo);
4101 remote_browser.sensitive_widgets =
4102 g_slist_append (remote_browser.sensitive_widgets, refresh_devices_button);
4103 remote_browser.sensitive_widgets =
4104 g_slist_append (remote_browser.sensitive_widgets, remote_box);
4105 remote_browser.sensitive_widgets =
4106 g_slist_append (remote_browser.sensitive_widgets, fs_combo);
4107
4108 g_idle_add (elektroid_load_devices_bg, NULL);
32804109 gtk_widget_show (main_window);
4110 audio_run (&audio);
4111
32814112 gtk_main ();
32824113
32834114 free (remote_browser.dir);
32844115
3285 if (connector_check (&connector))
3286 {
3287 connector_destroy (&connector);
3288 }
3289
3290 audio_destroy (&audio);
4116 if (backend_check (&backend))
4117 {
4118 backend_destroy (&backend);
4119 }
32914120
32924121 return EXIT_SUCCESS;
32934122 }
2323 #include <sys/types.h>
2424 #include <sys/stat.h>
2525 #include <unistd.h>
26 #include <glib/gi18n.h>
2627 #include "local.h"
27
28 static gint local_mkdir (const gchar *, void *);
29
30 static gint local_delete (const gchar *, void *);
31
32 static gint local_rename (const gchar *, const gchar *, void *);
33
34 static gint local_read_dir (struct item_iterator *, const gchar *, void *);
28 #include "sample.h"
29
30 struct local_iterator_data
31 {
32 DIR *dir;
33 gchar *path;
34 };
3535
3636 static gint local_copy_iterator (struct item_iterator *,
3737 struct item_iterator *, gboolean);
3838
39 static gint
40 local_download (struct backend *backend, const gchar * path,
41 GByteArray * output, struct job_control *control)
42 {
43 gint err;
44 gboolean active;
45
46 control->parts = 1;
47 control->part = 0;
48 set_job_control_progress (control, 0.0);
49
50 err = load_file (path, output, control);
51
52 g_mutex_lock (&control->mutex);
53 active = control->active;
54 g_mutex_unlock (&control->mutex);
55 if (active)
56 {
57 set_job_control_progress (control, 1.0);
58 }
59 else
60 {
61 err = -ECANCELED;
62 }
63
64 return err;
65 }
66
67 static gchar *
68 local_get_download_path (struct backend *backend,
69 struct item_iterator *remote_iter,
70 const struct fs_operations *ops,
71 const gchar * dst_dir, const gchar * src_path)
72 {
73 gchar *src_pathc = strdup (src_path);
74 gchar *path = malloc (PATH_MAX);
75 gchar *filename = basename (src_pathc);
76 remove_ext (filename);
77 snprintf (path, PATH_MAX, "%s/%s.wav", dst_dir, filename);
78 g_free (src_pathc);
79 return path;
80 }
81
82 static gchar *
83 local_get_upload_path (struct backend *backend,
84 struct item_iterator *remote_iter,
85 const struct fs_operations *ops,
86 const gchar * dst_dir,
87 const gchar * src_path, gint32 * next_index)
88 {
89 return local_get_download_path (backend, remote_iter, ops, dst_dir,
90 src_path);
91 }
92
93 gint
94 local_mkdir (struct backend *backend, const gchar * name)
95 {
96 DIR *dir;
97 gint res = 0;
98 gchar *dup;
99 gchar *parent;
100
101 dup = strdup (name);
102 parent = dirname (dup);
103
104 dir = opendir (parent);
105 if (dir)
106 {
107 closedir (dir);
108 }
109 else
110 {
111 res = local_mkdir (backend, parent);
112 if (res)
113 {
114 goto cleanup;
115 }
116 }
117
118 if (mkdir (name, 0755) == 0 || errno == EEXIST)
119 {
120 res = 0;
121 }
122 else
123 {
124 error_print ("Error while creating dir %s\n", name);
125 res = -errno;
126 }
127
128 cleanup:
129 g_free (dup);
130 return res;
131 }
132
133 static gint
134 local_delete (struct backend *backend, const gchar * path)
135 {
136 DIR *dir;
137 gchar *new_path;
138 struct dirent *dirent;
139
140 if ((dir = opendir (path)))
141 {
142 debug_print (1, "Deleting local %s dir...\n", path);
143
144 while ((dirent = readdir (dir)) != NULL)
145 {
146 if (strcmp (dirent->d_name, ".") == 0 ||
147 strcmp (dirent->d_name, "..") == 0)
148 {
149 continue;
150 }
151 new_path = chain_path (path, dirent->d_name);
152 local_delete (backend, new_path);
153 free (new_path);
154 }
155
156 closedir (dir);
157
158 return rmdir (path);
159 }
160 else
161 {
162 debug_print (1, "Deleting local %s file...\n", path);
163 return unlink (path);
164 }
165 }
166
167 static gint
168 local_rename (struct backend *backend, const gchar * old, const gchar * new)
169 {
170 debug_print (1, "Renaming locally from %s to %s...\n", old, new);
171 return rename (old, new);
172 }
173
174 static void
175 local_free_iterator_data (void *iter_data)
176 {
177 struct local_iterator_data *data = iter_data;
178 closedir (data->dir);
179 g_free (data->path);
180 g_free (data);
181 }
182
183 static guint
184 local_next_dentry (struct item_iterator *iter)
185 {
186 gchar *full_path;
187 struct dirent *dirent;
188 gboolean found;
189 struct stat st;
190 mode_t mode;
191 struct local_iterator_data *data = iter->data;
192
193 while ((dirent = readdir (data->dir)) != NULL)
194 {
195 if (dirent->d_name[0] == '.')
196 {
197 continue;
198 }
199
200 full_path = chain_path (data->path, dirent->d_name);
201 if (stat (full_path, &st))
202 {
203 free (full_path);
204 continue;
205 }
206
207 mode = st.st_mode & S_IFMT;
208 switch (mode)
209 {
210 case S_IFREG:
211 case S_IFDIR:
212 snprintf (iter->item.name, LABEL_MAX, "%s", dirent->d_name);
213 iter->item.type = mode == S_IFREG ? ELEKTROID_FILE : ELEKTROID_DIR;
214 iter->item.size = st.st_size;
215 found = TRUE;
216 break;
217 default:
218 error_print
219 ("stat mode neither file nor directory for %s\n", full_path);
220 found = FALSE;
221 }
222
223 free (full_path);
224
225 if (found)
226 {
227 return 0;
228 }
229 }
230
231 return -ENOENT;
232 }
233
234 static gint
235 local_init_iterator (struct item_iterator *iter, const gchar * path,
236 gboolean cached)
237 {
238 DIR *dir;
239 struct local_iterator_data *data;
240
241 if (!(dir = opendir (path)))
242 {
243 return -errno;
244 }
245
246 data = malloc (sizeof (struct local_iterator_data));
247 if (!data)
248 {
249 closedir (dir);
250 return -errno;
251 }
252
253 data->dir = dir;
254 data->path = strdup (path);
255
256 iter->data = data;
257 iter->next = local_next_dentry;
258 iter->free = local_free_iterator_data;
259 iter->copy = local_copy_iterator;
260
261 return 0;
262 }
263
264 static gint
265 local_read_dir (struct backend *backend, struct item_iterator *iter,
266 const gchar * path)
267 {
268 return local_init_iterator (iter, path, FALSE);
269 }
270
271 static gint
272 local_copy_iterator (struct item_iterator *dst, struct item_iterator *src,
273 gboolean cached)
274 {
275 struct local_iterator_data *data = src->data;
276 return local_init_iterator (dst, data->path, cached);
277 }
278
279 static gint
280 local_sample_load_custom (const gchar * path, GByteArray * sample,
281 struct job_control *control,
282 const struct sample_params *sample_params)
283 {
284 guint frames;
285 control->parts = 1;
286 control->part = 0;
287 gint err = sample_load_from_file (path, sample, control, sample_params,
288 &frames);
289 struct sample_info *sample_info = control->data;
290 sample_info->samplerate = sample_params->samplerate;
291 sample_info->channels =
292 sample_info->channels <
293 sample_params->channels ? sample_info->channels : sample_params->channels;
294 return err;
295 }
296
297 static gint
298 local_sample_load_48_16_stereo (const gchar * path, GByteArray * sample,
299 struct job_control *control)
300 {
301 struct sample_params sample_params;
302 sample_params.samplerate = 48000;
303 sample_params.channels = 2;
304 return local_sample_load_custom (path, sample, control, &sample_params);
305 }
306
307 static gint
308 local_sample_load_48_16_mono (const gchar * path, GByteArray * sample,
309 struct job_control *control)
310 {
311 struct sample_params sample_params;
312 sample_params.samplerate = 48000;
313 sample_params.channels = 1;
314 return local_sample_load_custom (path, sample, control, &sample_params);
315 }
316
317 static gint
318 local_upload (struct backend *backend, const gchar * path, GByteArray * input,
319 struct job_control *control)
320 {
321 return sample_save_from_array (path, input, control);
322 }
323
324 static gint
325 local_sample_load_441_16_stereo (const gchar * path, GByteArray * sample,
326 struct job_control *control)
327 {
328 struct sample_params sample_params;
329 sample_params.samplerate = 44100;
330 sample_params.channels = 2;
331 return local_sample_load_custom (path, sample, control, &sample_params);
332 }
333
334 static gint
335 local_sample_load_441_16_mono (const gchar * path, GByteArray * sample,
336 struct job_control *control)
337 {
338 struct sample_params sample_params;
339 sample_params.samplerate = 44100;
340 sample_params.channels = 1;
341 return local_sample_load_custom (path, sample, control, &sample_params);
342 }
343
39344 const struct fs_operations FS_LOCAL_OPERATIONS = {
40345 .fs = 0,
346 .options =
347 FS_OPTION_SORT_BY_NAME | FS_OPTION_AUDIO_PLAYER | FS_OPTION_STEREO,
348 .name = "local",
349 .gui_name = "localhost",
350 .gui_icon = BE_FILE_ICON_WAVE,
351 .readdir = local_read_dir,
352 .mkdir = local_mkdir,
353 .delete = local_delete,
354 .rename = local_rename,
355 .move = local_rename,
356 .get_ext = backend_get_fs_ext,
357 .type_ext = "wav",
358 .max_name_len = 255
359 };
360
361 enum sds_fs
362 {
363 FS_SAMPLES_LOCAL_48_16_STEREO = 0x1,
364 FS_SAMPLES_LOCAL_48_16_MONO = 0x2,
365 FS_SAMPLES_LOCAL_441_16_STEREO = 0x4,
366 FS_SAMPLES_LOCAL_441_16_MONO = 0x8
367 };
368
369 const struct fs_operations FS_SYSTEM_SAMPLES_48_16_STEREO_OPERATIONS = {
370 .fs = FS_SAMPLES_LOCAL_48_16_STEREO,
371 .options = FS_OPTION_SORT_BY_NAME | FS_OPTION_AUDIO_PLAYER |
372 FS_OPTION_STEREO | FS_OPTION_SHOW_SIZE_COLUMN,
373 .name = "wav4816s",
374 .gui_name = "WAV 48 KHz 16 bits stereo",
375 .gui_icon = BE_FILE_ICON_WAVE,
376 .readdir = local_read_dir,
377 .mkdir = local_mkdir,
378 .delete = local_delete,
379 .rename = local_rename,
380 .move = local_rename,
381 .download = local_download,
382 .upload = local_upload,
383 .load = local_sample_load_48_16_stereo,
384 .save = save_file,
385 .get_ext = backend_get_fs_ext,
386 .get_upload_path = local_get_upload_path,
387 .get_download_path = local_get_download_path,
388 .type_ext = "wav",
389 .max_name_len = 255
390 };
391
392 const struct fs_operations FS_SYSTEM_SAMPLES_48_16_MONO_OPERATIONS = {
393 .fs = FS_SAMPLES_LOCAL_48_16_MONO,
394 .options = FS_OPTION_SORT_BY_NAME | FS_OPTION_AUDIO_PLAYER |
395 FS_OPTION_SHOW_SIZE_COLUMN,
396 .name = "wav4816m",
397 .gui_name = "WAV 48 KHz 16 bits mono",
398 .gui_icon = BE_FILE_ICON_WAVE,
399 .readdir = local_read_dir,
400 .mkdir = local_mkdir,
401 .delete = local_delete,
402 .rename = local_rename,
403 .move = local_rename,
404 .download = local_download,
405 .upload = local_upload,
406 .load = local_sample_load_48_16_mono,
407 .save = save_file,
408 .get_ext = backend_get_fs_ext,
409 .get_upload_path = local_get_upload_path,
410 .get_download_path = local_get_download_path,
411 .type_ext = "wav",
412 .max_name_len = 255
413 };
414
415 const struct fs_operations FS_SYSTEM_SAMPLES_441_16_STEREO_OPERATIONS = {
416 .fs = FS_SAMPLES_LOCAL_441_16_STEREO,
417 .options =
418 FS_OPTION_SORT_BY_NAME | FS_OPTION_AUDIO_PLAYER |
419 FS_OPTION_STEREO | FS_OPTION_SHOW_SIZE_COLUMN,
420 .name = "wav44116s",
421 .gui_name = "WAV 44.1 KHz 16 bits stereo",
422 .gui_icon = BE_FILE_ICON_WAVE,
423 .readdir = local_read_dir,
424 .mkdir = local_mkdir,
425 .delete = local_delete,
426 .rename = local_rename,
427 .move = local_rename,
428 .download = local_download,
429 .upload = local_upload,
430 .load = local_sample_load_441_16_stereo,
431 .save = save_file,
432 .get_ext = backend_get_fs_ext,
433 .get_upload_path = local_get_upload_path,
434 .get_download_path = local_get_download_path,
435 .type_ext = "wav",
436 .max_name_len = 255
437 };
438
439 const struct fs_operations FS_SYSTEM_SAMPLES_441_16_MONO_OPERATIONS = {
440 .fs = FS_SAMPLES_LOCAL_441_16_MONO,
441 .options = FS_OPTION_SORT_BY_NAME | FS_OPTION_AUDIO_PLAYER |
442 FS_OPTION_SHOW_SIZE_COLUMN,
443 .name = "wav44116m",
444 .gui_name = "WAV 44.1 KHz 16 bits mono",
445 .gui_icon = BE_FILE_ICON_WAVE,
41446 .readdir = local_read_dir,
42447 .mkdir = local_mkdir,
43448 .delete = local_delete,
46451 .copy = NULL,
47452 .clear = NULL,
48453 .swap = NULL,
49 .download = NULL,
50 .upload = NULL,
51 .getid = get_item_name,
52 .extension = NULL
454 .download = local_download,
455 .upload = local_upload,
456 .load = local_sample_load_441_16_mono,
457 .save = save_file,
458 .get_ext = backend_get_fs_ext,
459 .get_upload_path = local_get_upload_path,
460 .get_download_path = local_get_download_path,
461 .type_ext = "wav",
462 .max_name_len = 255
463 };
464
465 static const struct fs_operations *FS_SYSTEM_OPERATIONS[] = {
466 &FS_SYSTEM_SAMPLES_48_16_STEREO_OPERATIONS,
467 &FS_SYSTEM_SAMPLES_48_16_MONO_OPERATIONS,
468 &FS_SYSTEM_SAMPLES_441_16_STEREO_OPERATIONS,
469 &FS_SYSTEM_SAMPLES_441_16_MONO_OPERATIONS,
470 NULL
53471 };
54472
55473 gint
56 local_mkdir (const gchar * name, void *data)
57 {
58 DIR *dir;
59 gint res = 0;
60 gchar *dup;
61 gchar *parent;
62
63 dup = strdup (name);
64 parent = dirname (dup);
65
66 dir = opendir (parent);
67 if (dir)
68 {
69 closedir (dir);
70 }
71 else
72 {
73 res = local_mkdir (parent, data);
74 if (res)
75 {
76 goto cleanup;
77 }
78 }
79
80 if (mkdir (name, 0755) == 0 || errno == EEXIST)
81 {
82 res = 0;
83 }
84 else
85 {
86 error_print ("Error while creating dir %s\n", name);
87 res = -errno;
88 }
89
90 cleanup:
91 g_free (dup);
92 return res;
93 }
94
95 static gint
96 local_delete (const gchar * path, void *data)
97 {
98 DIR *dir;
99 gchar *new_path;
100 struct dirent *dirent;
101
102 if ((dir = opendir (path)))
103 {
104 debug_print (1, "Deleting local %s dir...\n", path);
105
106 while ((dirent = readdir (dir)) != NULL)
107 {
108 if (strcmp (dirent->d_name, ".") == 0 ||
109 strcmp (dirent->d_name, "..") == 0)
110 {
111 continue;
112 }
113 new_path = chain_path (path, dirent->d_name);
114 local_delete (new_path, data);
115 free (new_path);
116 }
117
118 closedir (dir);
119
120 return rmdir (path);
121 }
122 else
123 {
124 debug_print (1, "Deleting local %s file...\n", path);
125 return unlink (path);
126 }
127 }
128
129 static gint
130 local_rename (const gchar * old, const gchar * new, void *data)
131 {
132 debug_print (1, "Renaming locally from %s to %s...\n", old, new);
133 return rename (old, new);
134 }
135
136 static void
137 local_free_iterator_data (void *iter_data)
138 {
139 struct local_iterator_data *data = iter_data;
140 closedir (data->dir);
141 g_free (data->path);
142 g_free (data);
143 }
144
145 static guint
146 local_next_dentry (struct item_iterator *iter)
147 {
148 gchar *full_path;
149 struct dirent *dirent;
150 gboolean found;
151 struct stat st;
152 mode_t mode;
153
154 struct local_iterator_data *data = iter->data;
155
156 if (iter->item.name != NULL)
157 {
158 g_free (iter->item.name);
159 }
160
161 while ((dirent = readdir (data->dir)) != NULL)
162 {
163 if (dirent->d_name[0] == '.')
164 {
165 continue;
166 }
167
168 full_path = chain_path (data->path, dirent->d_name);
169 if (stat (full_path, &st))
170 {
171 free (full_path);
172 continue;
173 }
174
175 mode = st.st_mode & S_IFMT;
176 switch (mode)
177 {
178 case S_IFREG:
179 case S_IFDIR:
180 iter->item.name = strdup (dirent->d_name);
181 iter->item.type = mode == S_IFREG ? ELEKTROID_FILE : ELEKTROID_DIR;
182 iter->item.size = st.st_size;
183 found = TRUE;
184 break;
185 default:
186 error_print
187 ("stat mode neither file nor directory for %s\n", full_path);
188 found = FALSE;
189 }
190
191 free (full_path);
192
193 if (found)
194 {
195 return 0;
196 }
197 }
198
199 return -ENOENT;
200 }
201
202 static gint
203 local_init_iterator (struct item_iterator *iter, const gchar * path,
204 gboolean cached)
205 {
206 DIR *dir;
207 struct local_iterator_data *data;
208
209 if (!(dir = opendir (path)))
210 {
211 return -errno;
212 }
213
214 data = malloc (sizeof (struct local_iterator_data));
215 if (!data)
216 {
217 closedir (dir);
218 return -errno;
219 }
220
221 data->dir = dir;
222 data->path = strdup (path);
223
224 iter->data = data;
225 iter->next = local_next_dentry;
226 iter->free = local_free_iterator_data;
227 iter->copy = local_copy_iterator;
228 iter->item.name = NULL;
229
474 system_handshake (struct backend *backend)
475 {
476 if (backend->type != BE_TYPE_SYSTEM)
477 {
478 return -ENODEV;
479 }
480 backend->device_desc.filesystems =
481 FS_SAMPLES_LOCAL_48_16_STEREO | FS_SAMPLES_LOCAL_48_16_MONO |
482 FS_SAMPLES_LOCAL_441_16_STEREO | FS_SAMPLES_LOCAL_441_16_MONO;
483 backend->fs_ops = FS_SYSTEM_OPERATIONS;
484 backend->destroy_data = backend_destroy_data;
485 snprintf (backend->device_name, LABEL_MAX, "%s", _("System"));
230486 return 0;
231487 }
232
233 static gint
234 local_read_dir (struct item_iterator *iter, const gchar * path,
235 void *userdata)
236 {
237 return local_init_iterator (iter, path, FALSE);
238 }
239
240 static gint
241 local_copy_iterator (struct item_iterator *dst, struct item_iterator *src,
242 gboolean cached)
243 {
244 struct local_iterator_data *data = src->data;
245 return local_init_iterator (dst, data->path, cached);
246 }
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #ifndef LOCAL_H
21 #define LOCAL_H
22
2023 #include <glib.h>
24 #include "backend.h"
2125 #include "utils.h"
2226
23 struct local_iterator_data
24 {
25 DIR *dir;
26 gchar *path;
27 };
27 extern const struct fs_operations FS_LOCAL_OPERATIONS;
2828
29 extern const struct fs_operations FS_LOCAL_OPERATIONS;
29 gint system_handshake (struct backend *);
30
31 #endif
2424 #include "notifier.h"
2525 #include "utils.h"
2626
27 void
28 notifier_init (struct notifier *notifier, struct browser *browser)
27 static void
28 notifier_set_dir (struct notifier *notifier)
2929 {
30 notifier->fd = inotify_init ();
31 notifier->wd = -1;
32 notifier->event_size = sizeof (struct inotify_event) + PATH_MAX;
33 notifier->event = malloc (notifier->event_size);
34 notifier->running = 1;
35 notifier->browser = browser;
36 }
37
38 void
39 notifier_set_dir (struct notifier *notifier, gchar * path)
40 {
41 debug_print (1, "Changing notifier path to %s...\n", path);
42 if (notifier->fd < 0)
30 debug_print (1, "Changing %s browser path to '%s'...\n",
31 notifier->browser->name, notifier->browser->dir);
32 if (!notifier->dir || strcmp (notifier->browser->dir, notifier->dir))
4333 {
44 return;
34 if (notifier->dir)
35 {
36 g_free (notifier->dir);
37 inotify_rm_watch (notifier->fd, notifier->wd);
38 g_thread_join (notifier->thread);
39 notifier->thread = NULL;
40 }
41 notifier->dir = strdup (notifier->browser->dir);
42 notifier->wd = inotify_add_watch (notifier->fd, notifier->dir,
43 IN_CREATE | IN_DELETE | IN_MOVED_FROM
44 | IN_DELETE_SELF | IN_MOVE_SELF
45 | IN_MOVED_TO | IN_IGNORED);
4546 }
46 if (notifier->wd >= 0)
47 {
48 inotify_rm_watch (notifier->fd, notifier->wd);
49 }
50 notifier->wd =
51 inotify_add_watch (notifier->fd, path,
52 IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_DELETE_SELF
53 | IN_MOVE_SELF | IN_MOVED_TO);
54 }
55
56 void
57 notifier_close (struct notifier *notifier)
58 {
59 if (notifier->fd < 0)
60 {
61 return;
62 }
63 if (notifier->wd >= 0)
64 {
65 inotify_rm_watch (notifier->fd, notifier->wd);
66 }
67 close (notifier->fd);
68 }
69
70 void
71 notifier_free (struct notifier *notifier)
72 {
73 free (notifier->event);
7447 }
7548
7649 static gboolean
8154 return FALSE;
8255 }
8356
84 gpointer
57 static gpointer
8558 notifier_run (gpointer data)
8659 {
8760 ssize_t size;
8861 struct notifier *notifier = data;
8962
90 while (notifier->running)
63 debug_print (1, "%s notifier running...\n", notifier->browser->name);
64
65 while (1)
9166 {
9267 size = read (notifier->fd, notifier->event, notifier->event_size);
93
94 if (size == 0 || size == EBADF)
68 if (size == 0)
9569 {
9670 break;
9771 }
98
99 if (size < 0)
72 if (size == -1)
10073 {
101 debug_print (2, "Error while reading notifier: %s\n",
102 g_strerror (errno));
103 continue;
74 if (errno != EBADF)
75 {
76 debug_print (2, "%s\n", g_strerror (errno));
77 }
78 break;
10479 }
10580
10681 if (notifier->event->mask & IN_CREATE
10883 || notifier->event->mask & IN_MOVED_FROM
10984 || notifier->event->mask & IN_MOVED_TO)
11085 {
111 debug_print (1, "Reloading local dir...\n");
86 debug_print (1, "Reloading dir...\n");
11287 g_idle_add (browser_load_dir, notifier->browser);
11388 }
11489 else if (notifier->event->mask & IN_DELETE_SELF
115 || notifier->event->mask & IN_MOVE_SELF ||
116 notifier->event->mask & IN_MOVED_TO)
90 || notifier->event->mask & IN_MOVE_SELF
91 || notifier->event->mask & IN_MOVED_TO)
11792 {
118 debug_print (1, "Loading local parent dir...\n");
93 debug_print (1, "Loading parent dir...\n");
11994 g_idle_add (notifier_go_up, notifier->browser);
95 break; //There is no directory to be nofified of.
96 }
97 else if ((notifier->event->mask & IN_IGNORED)) // inotify_rm_watch called
98 {
99 debug_print (1, "Finishing notifier...\n");
100 break;
120101 }
121102 else
122103 {
123 if (!(notifier->event->mask & IN_IGNORED))
124 {
125 error_print ("Unexpected event: %d\n", notifier->event->mask);
126 }
104 error_print ("Unexpected event: %d\n", notifier->event->mask);
127105 }
128106 }
129107
130108 return NULL;
131109 }
110
111 void
112 notifier_init (struct notifier *notifier, struct browser *browser)
113 {
114 notifier->fd = inotify_init ();
115 notifier->event_size = sizeof (struct inotify_event) + PATH_MAX;
116 notifier->event = malloc (notifier->event_size);
117 notifier->browser = browser;
118 notifier->thread = NULL;
119 notifier->dir = NULL;
120 g_mutex_init (&notifier->mutex);
121 }
122
123 void
124 notifier_set_active (struct notifier *notifier, gboolean active)
125 {
126 g_mutex_lock (&notifier->mutex);
127 if (active)
128 {
129 notifier_set_dir (notifier);
130 if (!notifier->thread)
131 {
132 debug_print (1, "Starting %s notifier...\n",
133 notifier->browser->name);
134 notifier->thread = g_thread_new ("notifier", notifier_run,
135 notifier);
136 }
137 }
138 else
139 {
140 if (notifier->thread)
141 {
142 debug_print (1, "Stopping %s notifier...\n",
143 notifier->browser->name);
144 inotify_rm_watch (notifier->fd, notifier->wd);
145 g_thread_join (notifier->thread);
146 notifier->thread = NULL;
147 close (notifier->fd);
148 }
149 }
150 g_mutex_unlock (&notifier->mutex);
151 }
152
153 void
154 notifier_destroy (struct notifier *notifier)
155 {
156 notifier_set_active (notifier, FALSE);
157 g_free (notifier->event);
158 }
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #ifndef NOTIFIER_H
21 #define NOTIFIER_H
22
2023 #include <sys/inotify.h>
2124 #include <gtk/gtk.h>
2225 #include "browser.h"
2326
2427 struct notifier
2528 {
29 gchar *dir;
2630 gint fd;
2731 gint wd;
2832 size_t event_size;
2933 struct inotify_event *event;
30 gint running;
3134 struct browser *browser;
35 GThread *thread;
36 GMutex mutex;
3237 };
3338
3439 void notifier_init (struct notifier *, struct browser *);
3540
36 void notifier_set_dir (struct notifier *, gchar *);
41 void notifier_set_active (struct notifier *, gboolean);
3742
38 void notifier_close (struct notifier *);
43 void notifier_destroy (struct notifier *);
3944
40 void notifier_free (struct notifier *);
41
42 gpointer notifier_run (gpointer);
45 #endif
+0
-770
src/package.c less more
0 /*
1 * package.c
2 * Copyright (C) 2021 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <json-glib/json-glib.h>
23 #include "package.h"
24 #include "utils.h"
25 #include "sample.h"
26
27 #define PKG_TAG_FORMAT_VERSION "FormatVersion"
28 #define PKG_TAG_PRODUCT_TYPE "ProductType"
29 #define PKG_TAG_PAYLOAD "Payload"
30 #define PKG_TAG_FILE_TYPE "FileType"
31 #define PKG_TAG_FIRMWARE_VERSION "FirmwareVersion"
32 #define PKG_TAG_SAMPLES "Samples"
33 #define PKG_TAG_FILE_NAME "FileName"
34 #define PKG_TAG_FILE_SIZE "FileSize"
35 #define PKG_TAG_HASH "Hash"
36 #define PKG_VAL_FILE_TYPE_PRJ "Project"
37 #define PKG_VAL_FILE_TYPE_SND "Sound"
38 #define PKG_VAL_FILE_TYPE_UNK "Unknown"
39
40 #define MAN_TAG_SAMPLE_REFS "sample_references"
41 #define MAN_TAG_HASH "hash"
42 #define MAN_TAG_SIZE "size"
43
44 #define MAX_PACKAGE_LEN (64 * 1024 * 1024)
45 #define MAX_MANIFEST_LEN (128 * 1024)
46 #define MANIFEST_FILENAME "manifest.json"
47
48 static gint
49 package_add_resource (struct package *pkg,
50 struct package_resource *pkg_resource, gboolean new)
51 {
52 zip_source_t *sample_source;
53 zip_int64_t index;
54 zip_error_t zerror;
55
56 debug_print (1, "Adding file %s to zip (%d B)...\n", pkg_resource->path,
57 pkg_resource->data->len);
58 sample_source =
59 zip_source_buffer_create (pkg_resource->data->data,
60 pkg_resource->data->len, 0, &zerror);
61 if (!sample_source)
62 {
63 error_print ("Error while creating file source: %s\n",
64 zip_error_strerror (&zerror));
65 zip_error_fini (&zerror);
66 return -1;
67 }
68
69 index =
70 zip_file_add (pkg->zip, pkg_resource->path, sample_source,
71 ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8);
72 if (index < 0)
73 {
74 error_print ("Error while adding file: %s\n",
75 zip_error_strerror (zip_get_error (pkg->zip)));
76 zip_source_free (sample_source);
77 return -1;
78 }
79
80 if (new)
81 {
82 pkg->resources = g_list_append (pkg->resources, pkg_resource);
83 }
84
85 return 0;
86 }
87
88
89 gint
90 package_begin (struct package *pkg, gchar * name, const gchar * fw_version,
91 const struct connector_device_desc *device_desc,
92 enum package_type type)
93 {
94 zip_error_t zerror;
95 pkg->resources = NULL;
96 pkg->buff = g_malloc (MAX_PACKAGE_LEN);
97 pkg->name = name;
98 pkg->fw_version = strdup (fw_version);
99 pkg->device_desc = device_desc;
100 pkg->type = type;
101
102 debug_print (1, "Creating zip buffer...\n");
103
104 zip_error_init (&zerror);
105 pkg->zip_source =
106 zip_source_buffer_create (pkg->buff, MAX_PACKAGE_LEN, 0, &zerror);
107 if (!pkg->zip_source)
108 {
109 error_print ("Error while creating zip source: %s\n",
110 zip_error_strerror (&zerror));
111 zip_error_fini (&zerror);
112 g_free (pkg->buff);
113 return -1;
114 }
115
116 pkg->zip = zip_open_from_source (pkg->zip_source, ZIP_TRUNCATE, &zerror);
117 if (!pkg->zip)
118 {
119 error_print ("Error while creating in memory zip: %s\n",
120 zip_error_strerror (&zerror));
121 zip_error_fini (&zerror);
122 zip_source_free (pkg->zip_source);
123 g_free (pkg->buff);
124 return -1;
125 }
126
127 zip_source_keep (pkg->zip_source);
128
129 pkg->manifest = g_malloc (sizeof (struct package_resource));
130 pkg->manifest->type = PKG_RES_TYPE_MANIFEST;
131 pkg->manifest->data = g_byte_array_sized_new (MAX_MANIFEST_LEN); //We need this because we can not resize later.
132 pkg->manifest->path = strdup (MANIFEST_FILENAME);
133 package_add_resource (pkg, pkg->manifest, TRUE);
134
135 return 0;
136 }
137
138 static gint
139 package_add_manifest (struct package *pkg)
140 {
141 JsonBuilder *builder;
142 JsonGenerator *gen;
143 JsonNode *root;
144 gchar *json;
145 gint len;
146 gchar *val = g_malloc (LABEL_MAX);
147 GList *resource;
148 gboolean samples_found = FALSE;
149 struct package_resource *pkg_resource;
150
151 builder = json_builder_new ();
152
153 json_builder_begin_object (builder);
154
155 json_builder_set_member_name (builder, PKG_TAG_FORMAT_VERSION);
156 json_builder_add_string_value (builder, "1.0");
157
158 json_builder_set_member_name (builder, PKG_TAG_PRODUCT_TYPE);
159 json_builder_begin_array (builder);
160 snprintf (val, LABEL_MAX, "%d", pkg->device_desc->id);
161 json_builder_add_string_value (builder, val);
162 json_builder_end_array (builder);
163
164 json_builder_set_member_name (builder, PKG_TAG_PAYLOAD);
165 json_builder_add_string_value (builder, pkg->name);
166
167 json_builder_set_member_name (builder, PKG_TAG_FILE_TYPE);
168 json_builder_add_string_value (builder,
169 pkg->type & PKG_FILE_TYPE_SOUND ?
170 PKG_VAL_FILE_TYPE_SND : pkg->type &
171 PKG_FILE_TYPE_PROJECT ? PKG_VAL_FILE_TYPE_PRJ
172 : PKG_VAL_FILE_TYPE_UNK);
173
174 if (pkg->type != PKG_FILE_TYPE_PRESET)
175 {
176 json_builder_set_member_name (builder, PKG_TAG_FIRMWARE_VERSION);
177 json_builder_add_string_value (builder, pkg->fw_version);
178 }
179
180 if (pkg->device_desc->filesystems & FS_SAMPLES)
181 {
182 for (resource = pkg->resources; resource; resource = resource->next)
183 {
184 pkg_resource = resource->data;
185 if (pkg_resource->type == PKG_RES_TYPE_SAMPLE)
186 {
187 samples_found = TRUE;
188 break;
189 }
190 }
191 }
192
193 if (samples_found)
194 {
195 json_builder_set_member_name (builder, PKG_TAG_SAMPLES);
196 json_builder_begin_array (builder);
197 for (resource = pkg->resources; resource; resource = resource->next)
198 {
199 pkg_resource = resource->data;
200 if (pkg_resource->type == PKG_RES_TYPE_SAMPLE)
201 {
202 json_builder_begin_object (builder);
203
204 json_builder_set_member_name (builder, PKG_TAG_FILE_NAME);
205 json_builder_add_string_value (builder, pkg_resource->path);
206
207 json_builder_set_member_name (builder, PKG_TAG_FILE_SIZE);
208 json_builder_add_int_value (builder, pkg_resource->size);
209
210 json_builder_set_member_name (builder, PKG_TAG_HASH);
211 snprintf (val, LABEL_MAX, "%d", pkg_resource->hash);
212 json_builder_add_string_value (builder, val);
213
214 json_builder_end_object (builder);
215 }
216 }
217 json_builder_end_array (builder);
218 }
219
220 json_builder_end_object (builder);
221
222 gen = json_generator_new ();
223 g_object_set (gen, "pretty", TRUE, NULL);
224 root = json_builder_get_root (builder);
225 json_generator_set_root (gen, root);
226 json = json_generator_to_data (gen, NULL);
227
228 len = strlen (json);
229 memcpy (pkg->manifest->data->data, json, len);
230 pkg->manifest->data->len = len;
231 package_add_resource (pkg, pkg->manifest, FALSE);
232
233 g_free (json);
234 json_node_free (root);
235 g_object_unref (gen);
236 g_object_unref (builder);
237 g_free (val);
238
239 return 0;
240 }
241
242 gint
243 package_end (struct package *pkg, GByteArray * out)
244 {
245 int ret = 0;
246 zip_stat_t zstat;
247
248 ret = package_add_manifest (pkg);
249 if (ret)
250 {
251 error_print ("Error while formatting %s\n", MANIFEST_FILENAME);
252 return ret;
253 }
254
255 debug_print (1, "Writing zip to buffer...\n");
256 if (zip_close (pkg->zip))
257 {
258 error_print ("Error while creating in memory zip: %s\n",
259 zip_error_strerror (zip_get_error (pkg->zip)));
260 return -1;
261 }
262
263 zip_source_stat (pkg->zip_source, &zstat);
264 debug_print (1, "%ld B written to package\n", zstat.comp_size);
265
266 zip_source_open (pkg->zip_source);
267 g_byte_array_set_size (out, zstat.comp_size);
268 zip_source_read (pkg->zip_source, out->data, zstat.comp_size);
269 zip_source_close (pkg->zip_source);
270
271 return 0;
272 }
273
274 void
275 package_free_package_resource (gpointer data)
276 {
277 struct package_resource *pkg_resource = data;
278 g_byte_array_free (pkg_resource->data, TRUE);
279 g_free (pkg_resource);
280 }
281
282 void
283 package_destroy (struct package *pkg)
284 {
285 zip_source_free (pkg->zip_source);
286 g_free (pkg->buff);
287 g_free (pkg->name);
288 g_free (pkg->fw_version);
289 g_list_free_full (pkg->resources, package_free_package_resource);
290 }
291
292 gint
293 package_open (struct package *pkg, GByteArray * data,
294 const struct connector_device_desc *device_desc)
295 {
296 gint ret;
297 zip_error_t zerror;
298 zip_file_t *manifest_file;
299 zip_stat_t zstat;
300
301 debug_print (1, "Opening zip stream...\n");
302
303 zip_error_init (&zerror);
304 pkg->zip_source =
305 zip_source_buffer_create (data->data, data->len, 0, &zerror);
306 if (!pkg->zip_source)
307 {
308 error_print ("Error while creating zip source: %s\n",
309 zip_error_strerror (&zerror));
310 zip_error_fini (&zerror);
311 return -1;
312 }
313
314 pkg->zip = zip_open_from_source (pkg->zip_source, ZIP_RDONLY, &zerror);
315 if (!pkg->zip)
316 {
317 error_print ("Error while creating in memory zip: %s\n",
318 zip_error_strerror (&zerror));
319 zip_error_fini (&zerror);
320 zip_source_free (pkg->zip_source);
321 return -1;
322 }
323
324 ret = zip_stat (pkg->zip, MANIFEST_FILENAME, ZIP_FL_ENC_STRICT, &zstat);
325 if (ret)
326 {
327 error_print ("Error while loading '%s': %s\n", MANIFEST_FILENAME,
328 zip_error_strerror (&zerror));
329 zip_error_fini (&zerror);
330 zip_source_free (pkg->zip_source);
331 zip_close (pkg->zip);
332 return -1;
333 }
334
335 pkg->manifest = g_malloc (sizeof (struct package_resource));
336 pkg->manifest->type = PKG_RES_TYPE_MANIFEST;
337 pkg->manifest->data = g_byte_array_sized_new (zstat.size);
338 pkg->manifest->path = strdup (MANIFEST_FILENAME);
339 manifest_file = zip_fopen (pkg->zip, MANIFEST_FILENAME, 0);
340 zip_fread (manifest_file, pkg->manifest->data->data, zstat.size);
341 pkg->manifest->data->len = zstat.size;
342 zip_fclose (manifest_file);
343
344 pkg->resources = NULL;
345 pkg->resources = g_list_append (pkg->resources, pkg->manifest);
346 pkg->buff = NULL;
347 pkg->name = NULL;
348 pkg->fw_version = NULL;
349 pkg->device_desc = device_desc;
350
351 return ret;
352 }
353
354 void
355 package_close (struct package *pkg)
356 {
357 zip_source_close (pkg->zip_source);
358 package_destroy (pkg);
359 }
360
361 gint
362 package_receive_pkg_resources (struct package *pkg,
363 const gchar * payload_path,
364 struct job_control *control,
365 struct connector *connector,
366 fs_remote_file_op download_data,
367 fs_remote_file_op download_sample)
368 {
369 gint ret, i, elements;
370 JsonParser *parser;
371 JsonReader *reader;
372 gint64 hash, size;
373 GError *error;
374 gchar *sample_path, *metadata_path;
375 struct package_resource *pkg_resource;
376 GByteArray *wave, *payload, *metadata, *sample;
377
378 metadata_path = chain_path (payload_path, ".metadata");
379 debug_print (1, "Getting metadata from %s...\n", metadata_path);
380 metadata = g_byte_array_new ();
381 control->parts = 130; // 128 sample slots, metadata and main.
382 control->part = 0;
383 set_job_control_progress (control, 0.0);
384 ret = download_data (metadata_path, metadata, control, connector);
385 if (ret)
386 {
387 debug_print (1, "Metadata file not available\n");
388 control->parts = 1;
389 goto get_payload;
390 }
391
392 control->part++;
393
394 parser = json_parser_new ();
395 if (!json_parser_load_from_data
396 (parser, (gchar *) metadata->data, metadata->len, &error))
397 {
398 error_print ("Unable to parse stream: %s. Continuing...",
399 error->message);
400 g_clear_error (&error);
401 control->parts = 2;
402 goto get_payload;
403 }
404
405 reader = json_reader_new (json_parser_get_root (parser));
406 if (!reader)
407 {
408 error_print ("Unable to read from parser. Continuing...");
409 control->parts = 2;
410 goto get_payload;
411 }
412
413 if (!json_reader_read_member (reader, MAN_TAG_SAMPLE_REFS))
414 {
415 debug_print (1, "Member '%s' not found\n", MAN_TAG_SAMPLE_REFS);
416 control->parts = 2;
417 goto get_payload;
418 }
419
420 if (!json_reader_is_array (reader))
421 {
422 error_print ("Member '%s' is not an array. Continuing...\n",
423 MAN_TAG_SAMPLE_REFS);
424 control->parts = 2;
425 goto cleanup_reader;
426 }
427
428 elements = json_reader_count_elements (reader);
429 if (!elements)
430 {
431 debug_print (1, "No samples found\n");
432 control->parts = 2;
433 goto cleanup_reader;
434 }
435
436 sample = g_byte_array_new ();
437 control->parts = 2 + elements;
438 set_job_control_progress (control, 0.0);
439 for (i = 0; i < elements; i++, control->part++)
440 {
441 if (!json_reader_read_element (reader, i))
442 {
443 error_print ("Cannot read element %d. Continuing...\n", i);
444 continue;
445 }
446 if (!json_reader_read_member (reader, MAN_TAG_HASH))
447 {
448 error_print ("Cannot read member '%s'. Continuing...\n",
449 MAN_TAG_HASH);
450 continue;
451 }
452 hash = json_reader_get_int_value (reader);
453 json_reader_end_element (reader);
454
455 if (!json_reader_read_member (reader, MAN_TAG_SIZE))
456 {
457 error_print ("Cannot read member '%s'. Continuing...\n",
458 MAN_TAG_SIZE);
459 continue;
460 }
461 size = json_reader_get_int_value (reader);
462 json_reader_end_element (reader);
463
464 json_reader_end_element (reader);
465
466 sample_path =
467 connector_get_sample_path_from_hash_size (connector, hash, size);
468 if (!sample_path)
469 {
470 debug_print (1, "Sample not found. Skipping...\n");
471 continue;
472 }
473
474 debug_print (1, "Hash: %ld; size: %ld; path: %s\n", hash, size,
475 sample_path);
476 debug_print (1, "Getting sample %s...\n", sample_path);
477 g_byte_array_set_size (sample, 0);
478 if (download_sample (sample_path, sample, control, connector))
479 {
480 g_free (sample_path);
481 error_print ("Error while downloading sample. Continuing...\n");
482 continue;
483 }
484
485 wave = g_byte_array_new ();
486 if (sample_wave (sample, wave, control))
487 {
488 error_print
489 ("Error while converting sample to wave file. Continuing...\n");
490 g_byte_array_free (wave, TRUE);
491 g_free (sample_path);
492 continue;
493 }
494 g_free (control->data);
495 control->data = NULL;
496
497 pkg_resource = g_malloc (sizeof (struct package_resource));
498 pkg_resource->type = PKG_RES_TYPE_SAMPLE;
499 pkg_resource->data = wave;
500 pkg_resource->hash = hash;
501 pkg_resource->size = size;
502 pkg_resource->path = g_malloc (PATH_MAX);
503 snprintf (pkg_resource->path, PATH_MAX, "%s%s.wav", PKG_TAG_SAMPLES,
504 sample_path);
505 if (package_add_resource (pkg, pkg_resource, TRUE))
506 {
507 package_free_package_resource (pkg_resource);
508 error_print ("Error while packaging sample\n");
509 continue;
510 }
511 }
512
513 g_byte_array_free (sample, TRUE);
514 cleanup_reader:
515 g_object_unref (reader);
516 g_object_unref (parser);
517 get_payload:
518 g_byte_array_free (metadata, TRUE);
519 debug_print (1, "Getting payload from %s...\n", payload_path);
520 payload = g_byte_array_new ();
521 ret = download_data (payload_path, payload, control, connector);
522 if (ret)
523 {
524 error_print ("Error while downloading payload\n");
525 ret = -1;
526 }
527 else
528 {
529 pkg_resource = g_malloc (sizeof (struct package_resource));
530 pkg_resource->type = PKG_RES_TYPE_PAYLOAD;
531 pkg_resource->data = payload;
532 pkg_resource->path = strdup (pkg->name);
533 if (package_add_resource (pkg, pkg_resource, TRUE))
534 {
535 package_free_package_resource (pkg_resource);
536 ret = -1;
537 }
538 }
539 return ret;
540 }
541
542 gint
543 package_send_pkg_resources (struct package *pkg,
544 const gchar * payload_path,
545 struct job_control *control,
546 struct connector *connector,
547 fs_remote_file_op upload_data,
548 fs_remote_file_op upload_sample)
549 {
550 gint elements, i, ret = 0;
551 const gchar *file_type, *sample_path;
552 gint64 product_type;
553 JsonParser *parser;
554 JsonReader *reader;
555 GError *error;
556 zip_stat_t zstat;
557 zip_error_t zerror;
558 zip_file_t *zip_file;
559 GByteArray *wave, *raw;
560 struct package_resource *pkg_resource;
561
562 zip_error_init (&zerror);
563
564 parser = json_parser_new ();
565 if (!json_parser_load_from_data
566 (parser, (gchar *) pkg->manifest->data->data, pkg->manifest->data->len,
567 &error))
568 {
569 error_print ("Unable to parse stream: %s", error->message);
570 g_clear_error (&error);
571 ret = -1;
572 goto cleanup_parser;
573 }
574
575 reader = json_reader_new (json_parser_get_root (parser));
576 if (!reader)
577 {
578 ret = -1;
579 goto cleanup_parser;
580 }
581
582 if (!json_reader_read_member (reader, PKG_TAG_PAYLOAD))
583 {
584 error_print ("No '%s' found\n", PKG_TAG_PAYLOAD);
585 ret = -1;
586 goto cleanup_reader;
587 }
588 pkg->name = strdup (json_reader_get_string_value (reader));
589 json_reader_end_element (reader);
590
591 if (zip_stat (pkg->zip, pkg->name, ZIP_FL_ENC_STRICT, &zstat))
592 {
593 error_print ("Error while loading '%s': %s\n", MANIFEST_FILENAME,
594 zip_error_strerror (&zerror));
595 zip_error_fini (&zerror);
596 ret = -1;
597 goto cleanup_reader;
598 }
599
600 pkg_resource = g_malloc (sizeof (struct package_resource));
601 pkg_resource->type = PKG_RES_TYPE_PAYLOAD;
602 pkg_resource->data = g_byte_array_sized_new (zstat.size);
603 pkg_resource->path = strdup (pkg->name);
604 zip_file = zip_fopen (pkg->zip, pkg->name, 0);
605 zip_fread (zip_file, pkg_resource->data->data, zstat.size);
606 pkg_resource->data->len = zstat.size;
607 zip_fclose (zip_file);
608
609 pkg->resources = g_list_append (pkg->resources, pkg_resource);
610
611 control->parts = 129; // 128 sample slots and main.
612 control->part = 0;
613 ret = upload_data (payload_path, pkg_resource->data, control, connector);
614 if (ret)
615 {
616 error_print ("Error while uploading payload to '%s'\n", payload_path);
617 goto cleanup_reader;
618 }
619 control->part++;
620
621 if (!json_reader_read_member (reader, PKG_TAG_FIRMWARE_VERSION))
622 {
623 error_print ("No '%s' found\n", PKG_TAG_FIRMWARE_VERSION);
624 ret = -1;
625 goto cleanup_reader;
626 }
627 pkg->fw_version = strdup (json_reader_get_string_value (reader));
628 json_reader_end_element (reader);
629
630 if (!json_reader_read_member (reader, PKG_TAG_FILE_TYPE))
631 {
632 error_print ("No '%s' found\n", PKG_TAG_FILE_TYPE);
633 ret = -1;
634 goto cleanup_reader;
635 }
636 file_type = json_reader_get_string_value (reader);
637 json_reader_end_element (reader);
638
639 if (strcmp (file_type, PKG_VAL_FILE_TYPE_SND) == 0)
640 {
641 pkg->type = PKG_FILE_TYPE_SOUND;
642 }
643 else if (strcmp (file_type, PKG_VAL_FILE_TYPE_PRJ) == 0)
644 {
645 pkg->type = PKG_FILE_TYPE_PROJECT;
646 }
647 else
648 {
649 pkg->type = PKG_FILE_TYPE_NONE;
650 debug_print (1, "Invalid '%s': %s\n", PKG_TAG_FILE_TYPE, file_type);
651 }
652
653 if (!json_reader_read_member (reader, PKG_TAG_PRODUCT_TYPE))
654 {
655 error_print ("No '%s' found\n", PKG_TAG_PRODUCT_TYPE);
656 ret = 0;
657 goto cleanup_reader;
658 }
659 if (!json_reader_is_array (reader))
660 {
661 error_print ("Member '%s' is not an array\n", PKG_TAG_PRODUCT_TYPE);
662 ret = -1;
663 goto cleanup_reader;
664 }
665 if (!json_reader_count_elements (reader))
666 {
667 error_print ("No product types found\n");
668 ret = 0;
669 goto cleanup_reader;
670 }
671 if (!json_reader_read_element (reader, 0))
672 {
673 ret = -1;
674 goto cleanup_reader;
675 }
676 product_type = atoi (json_reader_get_string_value (reader));
677 debug_print (1, "ProductType: %ld\n", product_type);
678 if (pkg->device_desc->id != product_type)
679 {
680 debug_print (1, "Incompatible product type. Continuing...\n");
681 }
682 json_reader_end_element (reader);
683 json_reader_end_element (reader);
684
685 if (!json_reader_read_member (reader, PKG_TAG_SAMPLES))
686 {
687 if (pkg->device_desc->filesystems & FS_SAMPLES)
688 {
689 debug_print (1, "No samples found\n");
690 }
691 control->parts = 1; // Only payload and it's done.
692 control->part = 0;
693 set_job_control_progress (control, 1.0);
694 goto cleanup_reader;
695 }
696
697 if (!json_reader_is_array (reader))
698 {
699 error_print ("Member '%s' is not an array. Skipping samples...\n",
700 PKG_TAG_SAMPLES);
701 ret = -1;
702 goto cleanup_reader;
703 }
704
705 wave = g_byte_array_sized_new (zstat.size);
706 raw = g_byte_array_sized_new (MAX_PACKAGE_LEN);
707 elements = json_reader_count_elements (reader);
708 control->parts = elements + 1;
709 for (i = 0; i < elements; i++, control->parts++)
710 {
711 json_reader_read_element (reader, i);
712 json_reader_read_member (reader, PKG_TAG_FILE_NAME);
713 sample_path = json_reader_get_string_value (reader);
714 json_reader_end_element (reader);
715 json_reader_end_element (reader);
716
717 if (zip_stat (pkg->zip, sample_path, ZIP_FL_ENC_STRICT, &zstat))
718 {
719 error_print ("Error while loading '%s': %s\n",
720 MANIFEST_FILENAME, zip_error_strerror (&zerror));
721 zip_error_fini (&zerror);
722 ret = -1;
723 continue;
724 }
725
726 g_byte_array_set_size (wave, zstat.size);
727 zip_file = zip_fopen (pkg->zip, sample_path, 0);
728 zip_fread (zip_file, wave->data, zstat.size);
729 wave->len = zstat.size;
730 zip_fclose (zip_file);
731
732 raw->len = 0;
733 if (sample_raw (wave, raw, control))
734 {
735 continue;
736 }
737
738 pkg_resource = g_malloc (sizeof (struct package_resource));
739 pkg_resource->type = PKG_RES_TYPE_SAMPLE;
740 pkg_resource->data = g_byte_array_sized_new (raw->len);
741 pkg_resource->data->len = raw->len;
742 memcpy (pkg_resource->data->data, raw->data, raw->len);
743 pkg_resource->path = strdup (sample_path);
744
745 pkg->resources = g_list_append (pkg->resources, pkg_resource);
746
747 //We remove the "Samples" at the beggining of the full zip path.
748 ret =
749 upload_sample (&sample_path[7], pkg_resource->data, control,
750 connector);
751 g_free (control->data);
752 control->data = NULL;
753 if (ret)
754 {
755 error_print ("Error while uploading sample to '%s'\n",
756 &sample_path[7]);
757 continue;
758 }
759 }
760
761 g_byte_array_free (wave, TRUE);
762 g_byte_array_free (raw, TRUE);
763
764 cleanup_reader:
765 g_object_unref (reader);
766 cleanup_parser:
767 g_object_unref (parser);
768 return ret;
769 }
+0
-83
src/package.h less more
0 /*
1 * package.h
2 * Copyright (C) 2021 David García Goñi <dagargo@gmail.com>
3 *
4 * This file is part of Elektroid.
5 *
6 * Elektroid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Elektroid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <glib.h>
21 #include <zip.h>
22 #include "connector.h"
23
24 enum package_resource_type
25 {
26 PKG_RES_TYPE_NONE,
27 PKG_RES_TYPE_PAYLOAD,
28 PKG_RES_TYPE_MANIFEST,
29 PKG_RES_TYPE_SAMPLE
30 };
31
32 struct package_resource
33 {
34 enum package_resource_type type;
35 guint32 hash;
36 guint32 size;
37 gchar *path;
38 GByteArray *data;
39 };
40
41 enum package_type
42 {
43 PKG_FILE_TYPE_NONE,
44 PKG_FILE_TYPE_SOUND,
45 PKG_FILE_TYPE_PROJECT,
46 PKG_FILE_TYPE_PRESET,
47 };
48
49 struct package
50 {
51 gchar *name;
52 enum package_type type;
53 gchar *fw_version;
54 const struct connector_device_desc *device_desc;
55 gchar *buff;
56 zip_source_t *zip_source;
57 zip_t *zip;
58 GList *resources;
59 struct package_resource *manifest;
60 };
61
62 gint package_begin (struct package *, gchar *, const gchar *,
63 const struct connector_device_desc *, enum package_type);
64
65 gint package_receive_pkg_resources (struct package *, const gchar *,
66 struct job_control *, struct connector *,
67 fs_remote_file_op, fs_remote_file_op);
68
69 gint package_end (struct package *, GByteArray *);
70
71 void package_destroy (struct package *);
72
73 gint package_open (struct package *, GByteArray *,
74 const struct connector_device_desc *);
75
76 gint package_send_pkg_resources (struct package *,
77 const gchar *,
78 struct job_control *,
79 struct connector *, fs_remote_file_op,
80 fs_remote_file_op);
81
82 void package_close (struct package *);
2727 #define PREFERENCES_FILE "/preferences.json"
2828
2929 #define MEMBER_AUTOPLAY "autoplay"
30 #define MEMBER_MIX "mix"
3031 #define MEMBER_LOCALDIR "localDir"
3132
3233 gint
6162 json_builder_set_member_name (builder, MEMBER_AUTOPLAY);
6263 json_builder_add_boolean_value (builder, preferences->autoplay);
6364
65 json_builder_set_member_name (builder, MEMBER_MIX);
66 json_builder_add_boolean_value (builder, preferences->mix);
67
6468 json_builder_set_member_name (builder, MEMBER_LOCALDIR);
6569 json_builder_add_string_value (builder, preferences->local_dir);
6670
8589 gint
8690 preferences_load (struct preferences *preferences)
8791 {
88 size_t n;
8992 GError *error;
9093 JsonReader *reader;
9194 JsonParser *parser = json_parser_new ();
99102 CONF_DIR PREFERENCES_FILE, error->message);
100103 g_error_free (error);
101104 g_object_unref (parser);
105 g_free (preferences_file);
102106 preferences->autoplay = TRUE;
107 preferences->mix = TRUE;
103108 preferences->local_dir = get_expanded_dir ("~");
104109 return 0;
105110 }
116121 }
117122 json_reader_end_member (reader);
118123
119 if (json_reader_read_member (reader, MEMBER_LOCALDIR))
124 if (json_reader_read_member (reader, MEMBER_MIX))
125 {
126 preferences->mix = json_reader_get_boolean_value (reader);
127 }
128 else
129 {
130 preferences->mix = TRUE;
131 }
132 json_reader_end_member (reader);
133
134 if (json_reader_read_member (reader, MEMBER_LOCALDIR) &&
135 g_file_test (json_reader_get_string_value (reader),
136 (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
120137 {
121138 preferences->local_dir = malloc (PATH_MAX);
122 n = PATH_MAX - 1;
123 strncpy (preferences->local_dir, json_reader_get_string_value (reader),
124 n);
125 preferences->local_dir[PATH_MAX - 1] = 0;
139 strcpy (preferences->local_dir, json_reader_get_string_value (reader));
126140 }
127141 else
128142 {
2222 struct preferences
2323 {
2424 gboolean autoplay;
25 gboolean mix;
2526 gchar *local_dir;
2627 };
2728
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #include "../config.h"
2120 #include <sndfile.h>
2221 #include <samplerate.h>
23 #include <inttypes.h>
22 #include <math.h>
23 #include <errno.h>
2424 #include "sample.h"
2525
2626 #define JUNK_CHUNK_ID "JUNK"
2727 #define SMPL_CHUNK_ID "smpl"
28
29 static const gchar *ELEKTROID_AUDIO_LOCAL_EXTS[] =
30 { "wav", "ogg", "aiff", "flac", NULL };
31
32 static const gchar *ELEKTROID_AUDIO_LOCAL_EXTS_MP3[] =
33 { "wav", "ogg", "aiff", "flac", "mp3", NULL };
2834
2935 struct smpl_chunk_data
3036 {
6167 0, 0, 0, 0
6268 };
6369
64 static sf_count_t get_filelen_byte_array_io (void *);
65 static sf_count_t seek_byte_array_io (sf_count_t, int, void *);
66 static sf_count_t read_byte_array_io (void *, sf_count_t, void *);
67 static sf_count_t write_byte_array_io (const void *, sf_count_t, void *);
68 static sf_count_t tell_byte_array_io (void *);
69
70 static SF_VIRTUAL_IO G_BYTE_ARRAY_IO = {
71 .get_filelen = get_filelen_byte_array_io,
72 .seek = seek_byte_array_io,
73 .read = read_byte_array_io,
74 .write = write_byte_array_io,
75 .tell = tell_byte_array_io
76 };
77
7870 static sf_count_t
7971 get_filelen_byte_array_io (void *user_data)
8072 {
148140 return data->pos;
149141 }
150142
143 static SF_VIRTUAL_IO G_BYTE_ARRAY_IO = {
144 .get_filelen = get_filelen_byte_array_io,
145 .seek = seek_byte_array_io,
146 .read = read_byte_array_io,
147 .write = write_byte_array_io,
148 .tell = tell_byte_array_io
149 };
150
151 static sf_count_t
152 get_filelen_file_io (void *user_data)
153 {
154 long fileSize, position;
155 FILE *file = user_data;
156 position = fseek (file, 0, SEEK_END);
157 fileSize = ftell (file);
158 fseek (file, position, SEEK_SET);
159 return fileSize;
160 }
161
162 static sf_count_t
163 seek_file_io (sf_count_t offset, int whence, void *user_data)
164 {
165 FILE *file = user_data;
166 return fseek (file, offset, whence);
167 }
168
169 static sf_count_t
170 read_file_io (void *ptr, sf_count_t count, void *user_data)
171 {
172 FILE *file = user_data;
173 return fread (ptr, 1, count, file);
174 }
175
176 static sf_count_t
177 write_file_io (const void *ptr, sf_count_t count, void *user_data)
178 {
179 FILE *file = user_data;
180 return fwrite (ptr, 1, count, file);
181 }
182
183 static sf_count_t
184 tell_file_io (void *user_data)
185 {
186 FILE *file = user_data;
187 return ftell (file);
188 }
189
190 static SF_VIRTUAL_IO FILE_IO = {
191 .get_filelen = get_filelen_file_io,
192 .seek = seek_file_io,
193 .read = read_file_io,
194 .write = write_file_io,
195 .tell = tell_file_io
196 };
197
151198 static gint
152 sample_wave_data (GByteArray * sample,
153 struct job_control *control,
154 struct g_byte_array_io_data *wave)
199 sample_get_wave_data (GByteArray * sample, struct job_control *control,
200 struct g_byte_array_io_data *wave)
155201 {
156202 SF_INFO sf_info;
157203 SNDFILE *sndfile;
159205 struct SF_CHUNK_INFO junk_chunk_info;
160206 struct SF_CHUNK_INFO smpl_chunk_info;
161207 struct smpl_chunk_data smpl_chunk_data;
162 struct sample_loop_data *sample_loop_data = control->data;
208 struct sample_info *sample_info = control->data;
163209
164210 g_byte_array_set_size (wave->array, sample->len + 1024); //We need space for the headers.
165211 wave->array->len = 0;
166212
213 frames = sample->len >> sample_info->channels;
214 debug_print (1, "Frames: %" PRIu64 "; sample rate: %d; channels: %d\n",
215 frames, sample_info->samplerate, sample_info->channels);
167216 debug_print (1, "Loop start at %d; loop end at %d\n",
168 sample_loop_data->start, sample_loop_data->end);
217 sample_info->loopstart, sample_info->loopend);
169218
170219 memset (&sf_info, 0, sizeof (sf_info));
171 sf_info.samplerate = ELEKTRON_SAMPLE_RATE;
172 sf_info.channels = 1;
220 sf_info.samplerate = sample_info->samplerate;
221 sf_info.channels = sample_info->channels;
173222 sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
174223 sndfile = sf_open_virtual (&G_BYTE_ARRAY_IO, SFM_WRITE, &sf_info, wave);
175224 if (!sndfile)
189238
190239 smpl_chunk_data.manufacturer = 0;
191240 smpl_chunk_data.product = 0;
192 smpl_chunk_data.sample_period = 1000000000 / ELEKTRON_SAMPLE_RATE;
241 smpl_chunk_data.sample_period = 1e9 / sample_info->samplerate;
193242 smpl_chunk_data.midi_unity_note = 60;
194243 smpl_chunk_data.midi_pitch_fraction = 0;
195244 smpl_chunk_data.smpte_format = 0;
197246 smpl_chunk_data.num_sampler_loops = 1;
198247 smpl_chunk_data.sampler_data = 0;
199248 smpl_chunk_data.sample_loop.cue_point_id = 0;
200 smpl_chunk_data.sample_loop.type = ELEKTRON_LOOP_TYPE;
201 smpl_chunk_data.sample_loop.start = sample_loop_data->start;
202 smpl_chunk_data.sample_loop.end = sample_loop_data->end;
249 smpl_chunk_data.sample_loop.type = sample_info->looptype;
250 smpl_chunk_data.sample_loop.start = sample_info->loopstart;
251 smpl_chunk_data.sample_loop.end = sample_info->loopend;
203252 smpl_chunk_data.sample_loop.fraction = 0;
204253 smpl_chunk_data.sample_loop.play_count = 0;
205254
212261 error_print ("%s\n", sf_strerror (sndfile));
213262 }
214263
215 frames = sample->len >> 1;
216 total = sf_write_short (sndfile, (gint16 *) sample->data, frames);
217
264 total = sf_writef_short (sndfile, (gint16 *) sample->data, frames);
218265 sf_close (sndfile);
219266
220267 if (total != frames)
221268 {
222 error_print ("Unexpected frames while writing to sample (%ld != %ld)\n",
223 total, frames);
269 error_print ("Unexpected frames while writing to file (%" PRIu64 " != %"
270 PRIu64 ")\n", total, frames);
224271 return -1;
225272 }
226273
228275 }
229276
230277 gint
231 sample_wave (GByteArray * sample, GByteArray * wave,
232 struct job_control *control)
278 sample_get_wav_from_array (GByteArray * sample, GByteArray * wave,
279 struct job_control *control)
233280 {
234281 struct g_byte_array_io_data data;
235282 data.pos = 0;
236283 data.array = wave;
237 return sample_wave_data (sample, control, &data);
284 return sample_get_wave_data (sample, control, &data);
238285 }
239286
240287 gint
241 sample_save (const gchar * path, GByteArray * sample,
242 struct job_control *control)
288 sample_save_from_array (const gchar * path, GByteArray * sample,
289 struct job_control *control)
243290 {
244291 GByteArray *wave = g_byte_array_new ();
245 gint ret = sample_wave (sample, wave, control);
292 gint ret = sample_get_wav_from_array (sample, wave, control);
246293 if (!ret)
247294 {
248295 ret = save_file (path, wave, control);
271318 }
272319 }
273320
321 // If control->data is NULL, then a new struct sample_info * is created and control->data points to it.
322 // In case of failure, if control->data is NULL is freed.
323 // Franes is the amount of frames after resampling. This value is set before the loading has terminated.
324
274325 static gint
275 sample_raw_data (struct g_byte_array_io_data *wave,
326 sample_load_raw (void *data, SF_VIRTUAL_IO * sf_virtual_io,
276327 struct job_control *control, GByteArray * sample,
277 guint * frames)
328 const struct sample_params *sample_params, guint * frames)
278329 {
279330 SF_INFO sf_info;
280331 SNDFILE *sndfile;
287338 gint16 *buffer_input_mono;
288339 gint16 *buffer_s;
289340 gfloat *buffer_f;
290 gint err;
291 gint resampled_buffer_len;
292 gint f, frames_read;
341 gint err, resampled_buffer_len, f, frames_read, channels, samplerate;
293342 gboolean active;
294 struct sample_loop_data *sample_loop_data;
343 gdouble ratio;
344 struct sample_info *sample_info;
295345 struct smpl_chunk_data smpl_chunk_data;
346 gboolean disable_loop = FALSE;
296347
297348 if (control)
298349 {
305356 }
306357
307358 sf_info.format = 0;
308 sndfile = sf_open_virtual (&G_BYTE_ARRAY_IO, SFM_READ, &sf_info, wave);
359 sndfile = sf_open_virtual (sf_virtual_io, SFM_READ, &sf_info, data);
309360 if (!sndfile)
310361 {
311362 error_print ("%s\n", sf_strerror (sndfile));
315366 strcpy (chunk_info.id, SMPL_CHUNK_ID);
316367 chunk_info.id_size = strlen (SMPL_CHUNK_ID);
317368 chunk_iter = sf_get_chunk_iterator (sndfile, &chunk_info);
318 sample_loop_data = malloc (sizeof (struct sample_loop_data));
369 sample_info = control->data;
370 if (!control->data)
371 {
372 sample_info = g_malloc (sizeof (struct sample_info));
373 }
374
375 channels = sample_params->channels == 2 && sf_info.channels == 2 ? 2 : 1;
376 samplerate =
377 sample_params->samplerate ? sample_params->
378 samplerate : sf_info.samplerate;
379
380 if (control)
381 {
382 g_mutex_lock (&control->mutex);
383 }
384 sample_info->channels = sf_info.channels;
385 sample_info->samplerate = sf_info.samplerate;
386 sample_info->frames = sf_info.frames;
387 if (control)
388 {
389 g_mutex_unlock (&control->mutex);
390 }
391
319392 if (chunk_iter)
320393 {
321394 chunk_info.datalen = sizeof (struct smpl_chunk_data);
395 memset (&smpl_chunk_data, 0, chunk_info.datalen);
322396 chunk_info.data = &smpl_chunk_data;
323397 sf_get_chunk_data (chunk_iter, &chunk_info);
324398
325 sample_loop_data->start = le32toh (smpl_chunk_data.sample_loop.start);
326 sample_loop_data->end = le32toh (smpl_chunk_data.sample_loop.end);
399 if ((sf_info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
400 {
401 switch (sf_info.format & SF_FORMAT_SUBMASK)
402 {
403 case SF_FORMAT_PCM_S8:
404 sample_info->bitdepth = 8;
405 break;
406 case SF_FORMAT_PCM_16:
407 sample_info->bitdepth = 16;
408 break;
409 case SF_FORMAT_PCM_24:
410 sample_info->bitdepth = 24;
411 break;
412 case SF_FORMAT_PCM_32:
413 sample_info->bitdepth = 32;
414 break;
415 default:
416 sample_info->bitdepth = 0;
417 }
418 }
419 else
420 {
421 sample_info->bitdepth = 0;
422 }
423 sample_info->loopstart = le32toh (smpl_chunk_data.sample_loop.start);
424 sample_info->loopend = le32toh (smpl_chunk_data.sample_loop.end);
425 sample_info->looptype = le32toh (smpl_chunk_data.sample_loop.type);
426 if (sample_info->loopstart >= sf_info.frames)
427 {
428 debug_print (2, "Bad loop start\n");
429 disable_loop = TRUE;
430 }
431 if (sample_info->loopend >= sf_info.frames)
432 {
433 debug_print (2, "Bad loop end\n");
434 disable_loop = TRUE;
435 }
327436 }
328437 else
329438 {
330 sample_loop_data->start = 0;
331 sample_loop_data->end = 0;
332 }
333
334 control->data = sample_loop_data;
439 disable_loop = TRUE;
440 }
441 if (disable_loop)
442 {
443 sample_info->loopstart = sf_info.frames - 1;
444 sample_info->loopend = sample_info->loopstart;
445 sample_info->looptype = 0;
446 }
447 sample_info->bitdepth = 16;
335448
336449 //Set scale factor. See http://www.mega-nerd.com/libsndfile/api.html#note2
337450 if ((sf_info.format & SF_FORMAT_FLOAT) == SF_FORMAT_FLOAT ||
346459 malloc (LOAD_BUFFER_LEN * sf_info.channels * sizeof (gint16));
347460 buffer_input_mono = malloc (LOAD_BUFFER_LEN * sizeof (gint16));
348461
349 buffer_f = malloc (LOAD_BUFFER_LEN * sizeof (gfloat));
462 buffer_f = malloc (LOAD_BUFFER_LEN * channels * sizeof (gfloat));
350463 src_data.data_in = buffer_f;
351 src_data.src_ratio = ((double) ELEKTRON_SAMPLE_RATE) / sf_info.samplerate;
352
353 resampled_buffer_len = LOAD_BUFFER_LEN * src_data.src_ratio;
464 ratio = samplerate / (double) sf_info.samplerate;
465 src_data.src_ratio = ratio;
466
467 src_data.output_frames = ceil (LOAD_BUFFER_LEN * src_data.src_ratio);
468 resampled_buffer_len = src_data.output_frames * channels;
354469 buffer_s = malloc (resampled_buffer_len * sizeof (gint16));
355470 src_data.data_out = malloc (resampled_buffer_len * sizeof (gfloat));
356471
357 src_state = src_new (SRC_SINC_BEST_QUALITY, 1, &err);
472 src_state = src_new (SRC_SINC_BEST_QUALITY, channels, &err);
358473 if (err)
359474 {
360475 goto cleanup;
361476 }
362477
363 if (frames)
364 {
365 *frames = sf_info.frames * src_data.src_ratio;
366 }
367
368 if (ELEKTRON_SAMPLE_RATE != sf_info.samplerate)
478 *frames = sf_info.frames * src_data.src_ratio;
479
480 if (samplerate != sf_info.samplerate)
369481 {
370482 debug_print (2, "Loop start at %d, loop end at %d before resampling\n",
371 sample_loop_data->start, sample_loop_data->end);
372 sample_loop_data->start *= src_data.src_ratio;
373 sample_loop_data->end *= src_data.src_ratio;
483 sample_info->loopstart, sample_info->loopend);
484 sample_info->loopstart = round (sample_info->loopstart * ratio);
485 sample_info->loopend = round (sample_info->loopend * ratio);
374486 debug_print (2, "Loop start at %d, loop end at %d after resampling\n",
375 sample_loop_data->start, sample_loop_data->end);
487 sample_info->loopstart, sample_info->loopend);
376488 }
377489
378490 debug_print (2, "Loading sample (%" PRId64 " frames)...\n", sf_info.frames);
379491
380 f = 0;
381492 if (control)
382493 {
383494 g_mutex_lock (&control->mutex);
389500 active = TRUE;
390501 }
391502
503 f = 0;
392504 while (f < sf_info.frames && active)
393505 {
394 debug_print (2, "Loading buffer...\n");
395
396 frames_read =
397 sf_readf_short (sndfile, buffer_input_multi, LOAD_BUFFER_LEN);
398
399 if (frames_read < LOAD_BUFFER_LEN)
400 {
401 src_data.end_of_input = SF_TRUE;
402 }
403 else
404 {
405 src_data.end_of_input = 0;
406 }
407 src_data.input_frames = frames_read;
506 debug_print (2, "Loading %d channels buffer...\n", channels);
507 frames_read = sf_readf_short (sndfile, buffer_input_multi,
508 LOAD_BUFFER_LEN);
408509 f += frames_read;
409510
410 if (sf_info.channels == 1)
511 if (channels == sf_info.channels) // 1 <= channels <= 2
411512 {
412513 buffer_input = buffer_input_multi;
413514 }
418519 buffer_input = buffer_input_mono;
419520 }
420521
421 if (sf_info.samplerate == ELEKTRON_SAMPLE_RATE)
522 if (samplerate == sf_info.samplerate)
422523 {
423524 if (control)
424525 {
425526 g_mutex_lock (&control->mutex);
426527 }
427528 g_byte_array_append (sample, (guint8 *) buffer_input,
428 frames_read << 1);
529 frames_read << channels);
429530 if (control)
430531 {
431532 g_mutex_unlock (&control->mutex);
433534 }
434535 else
435536 {
436 src_short_to_float_array (buffer_input, buffer_f, frames_read);
437 src_data.output_frames = src_data.input_frames * src_data.src_ratio;
537 src_data.end_of_input = frames_read < LOAD_BUFFER_LEN ? SF_TRUE : 0;
538 src_data.input_frames = frames_read;
539
540 src_short_to_float_array (buffer_input, buffer_f,
541 frames_read * channels);
542 debug_print (2, "Resampling %d channels with ratio %f...\n",
543 channels, src_data.src_ratio);
438544 err = src_process (src_state, &src_data);
439 debug_print (2, "Resampling...\n");
440545 if (err)
441546 {
442 debug_print (2, "Error %s\n", src_strerror (err));
547 g_byte_array_set_size (sample, 0);
548 error_print ("Error while resampling: %s\n",
549 src_strerror (err));
443550 break;
444551 }
445552 src_float_to_short_array (src_data.data_out, buffer_s,
446 src_data.output_frames_gen);
553 src_data.output_frames_gen * channels);
447554 if (control)
448555 {
449556 g_mutex_lock (&control->mutex);
450557 }
451558 g_byte_array_append (sample, (guint8 *) buffer_s,
452 src_data.output_frames_gen << 1);
559 src_data.output_frames_gen << channels);
453560 if (control)
454561 {
455562 g_mutex_unlock (&control->mutex);
458565
459566 if (control)
460567 {
461 control->callback (f * 1.0 / sf_info.frames);
462568 g_mutex_lock (&control->mutex);
569 set_job_control_progress_no_sync (control,
570 f * 1.0 / sf_info.frames);
463571 active = control->active;
464572 g_mutex_unlock (&control->mutex);
465573 }
467575
468576 src_delete (src_state);
469577
470 if (err)
471 {
472 error_print ("Error while preparing resampling: %s\n",
473 src_strerror (err));
474 }
475
476578 if (control)
477579 {
478580 g_mutex_lock (&control->mutex);
479581
480582 if (control->active)
481583 {
482 control->callback (1.0);
584 set_job_control_progress_no_sync (control, 1.0);
483585 }
484586 else
485587 {
498600
499601 sf_close (sndfile);
500602
501 if (!sample->len)
502 {
503 g_free (control->data);
504 }
505
506 return sample->len > 0 ? 0 : -1;
507 }
508
509 static gint
510 sample_raw_frames (GByteArray * wave, GByteArray * sample,
511 struct job_control *control, guint * frames)
603 if (sample->len)
604 {
605 if (!control->data)
606 {
607 control->data = sample_info;
608 }
609 // This removes the additional samples added by the resampler due to rounding.
610 g_byte_array_set_size (sample, *frames << channels);
611 return 0;
612 }
613 else
614 {
615 if (!control->data)
616 {
617 g_free (sample_info);
618 }
619 return -1;
620 }
621 }
622
623 gint
624 sample_load_from_array (GByteArray * wave, GByteArray * sample,
625 struct job_control *control,
626 const struct sample_params *sample_params,
627 guint * frames)
512628 {
513629 struct g_byte_array_io_data data;
514630 data.pos = 0;
515631 data.array = wave;
516 return sample_raw_data (&data, control, sample, frames);
632 return sample_load_raw (&data, &G_BYTE_ARRAY_IO, control, sample,
633 sample_params, frames);
517634 }
518635
519636 gint
520 sample_raw (GByteArray * wave, GByteArray * sample,
521 struct job_control *control)
522 {
523 return sample_raw_frames (wave, sample, control, NULL);
524 }
525
526 gint
527 sample_load_with_frames (const gchar * path, GByteArray * sample,
528 struct job_control *control, guint * frames)
529 {
530 GByteArray *wave = g_byte_array_new ();
531
532 debug_print (1, "Loading file %s...\n", path);
533
534 int ret = load_file (path, wave, control);
535 if (!ret)
536 {
537 ret = sample_raw_frames (wave, sample, control, frames);
538 }
539 g_byte_array_free (wave, TRUE);
540 return ret;
541 }
542
543 gint
544 sample_load (const gchar * path, GByteArray * sample,
545 struct job_control *control)
546 {
547 return sample_load_with_frames (path, sample, control, NULL);
548 }
549
550 gboolean
637 sample_load_from_file (const gchar * path, GByteArray * sample,
638 struct job_control *control,
639 const struct sample_params *sample_params,
640 guint * frames)
641 {
642 FILE *file = fopen (path, "rb");
643 if (!file)
644 {
645 return errno;
646 }
647 gint err = sample_load_raw (file, &FILE_IO, control, sample, sample_params,
648 frames);
649 fclose (file);
650 return err;
651 }
652
653 static gboolean
551654 sample_is_mp3_supported ()
552655 {
553656 static char buffer[LABEL_MAX];
561664
562665 return FALSE;
563666 }
667
668 const gchar **
669 sample_get_sample_extensions ()
670 {
671 if (sample_is_mp3_supported ())
672 {
673 return ELEKTROID_AUDIO_LOCAL_EXTS_MP3;
674 }
675 return ELEKTROID_AUDIO_LOCAL_EXTS;
676 }
2525 #ifndef SAMPLE_H
2626 #define SAMPLE_H
2727
28 #define LOAD_BUFFER_LEN 4800 // In guint16 frames; 9600 B; 0.1 ms
28 #define LOAD_BUFFER_LEN 9600 // In guint16 frames; 0.2 ms
2929
30 gint sample_wave (GByteArray *, GByteArray *, struct job_control *);
30 gint sample_get_wav_from_array (GByteArray *, GByteArray *,
31 struct job_control *);
3132
32 gint sample_raw (GByteArray *, GByteArray *, struct job_control *);
33 gint sample_save_from_array (const gchar *, GByteArray *,
34 struct job_control *);
3335
34 gint sample_save (const gchar *, GByteArray *, struct job_control *);
36 gint sample_load_from_array (GByteArray *, GByteArray *, struct job_control *,
37 const struct sample_params *, guint *);
3538
36 gint sample_load (const gchar *, GByteArray *, struct job_control *);
39 gint sample_load_from_file (const gchar *, GByteArray *, struct job_control *,
40 const struct sample_params *, guint *);
3741
38 gint sample_load_with_frames (const gchar *, GByteArray *,
39 struct job_control *, guint *);
40
41 gboolean sample_is_mp3_supported ();
42 const gchar **sample_get_sample_extensions ();
4243
4344 #endif
2323 #include "utils.h"
2424
2525 #define DEBUG_SHORT_HEX_LEN 64
26 #define DEBUG_FULL_HEX_THRES 3
26 #define DEBUG_FULL_HEX_THRES 5
2727
2828 #define KIB 1024
29
30 #define DEVICES_FILE "/devices.json"
31
32 #define DEV_TAG_ID "id"
33 #define DEV_TAG_NAME "name"
34 #define DEV_TAG_ALIAS "alias"
35 #define DEV_TAG_FILESYSTEMS "filesystems"
36 #define DEV_TAG_STORAGE "storage"
3729
3830 gint debug_level;
3931
137129 remove_ext (char *name)
138130 {
139131 gint namelen = strlen (name);
140 gchar *dot = &name[namelen];
141 gint i = namelen;
142
143 while (*dot != '.' && i > 0)
144 {
132 gchar *dot = &name[namelen - 1];
133 gint i = namelen - 1;
134
135 while (i > 0)
136 {
137 if (*dot == '.')
138 {
139 *dot = 0;
140 break;
141 }
145142 dot--;
146143 i--;
147144 }
148 *dot = 0;
149145 }
150146
151147 const gchar *
224220 }
225221
226222 gchar *
227 get_item_name (struct item *item)
228 {
223 get_filename (guint32 fs_options, struct item *item)
224 {
225 if (fs_options & FS_OPTION_ID_AS_FILENAME && item->type == ELEKTROID_FILE)
226 {
227 gchar *id = malloc (LABEL_MAX);
228 snprintf (id, LABEL_MAX, "%d", item->id);
229 return id;
230 }
229231 return strdup (item->name);
230 }
231
232 gchar *
233 get_item_index (struct item *item)
234 {
235 gchar *index;
236
237 if (item->type == ELEKTROID_DIR)
238 {
239 index = get_item_name (item);
240 }
241 else
242 {
243 index = malloc (LABEL_MAX);
244 snprintf (index, LABEL_MAX, "%d", item->index);
245 }
246
247 return index;
248232 }
249233
250234 guint
262246 }
263247 }
264248
265 gint
249 inline gint
266250 copy_item_iterator (struct item_iterator *dst, struct item_iterator *src,
267251 gboolean cached)
268252 {
273257 load_file (const char *path, GByteArray * array, struct job_control *control)
274258 {
275259 FILE *file;
276 long size;
260 size_t size;
277261 gint res;
278262
279263 file = fopen (path, "rb");
299283
300284 if (fread (array->data, 1, size, file) == size)
301285 {
302 debug_print (1, "%zu bytes read\n", size);
286 debug_print (1, "%zu B read\n", size);
303287 }
304288 else
305289 {
316300 save_file_char (const gchar * path, const guint8 * data, ssize_t len)
317301 {
318302 gint res;
319 long bytes;
303 size_t bytes;
320304 FILE *file;
321305
322306 file = fopen (path, "w");
332316 bytes = fwrite (data, 1, len, file);
333317 if (bytes == len)
334318 {
335 debug_print (1, "%zu bytes written\n", bytes);
319 debug_print (1, "%zu B written\n", bytes);
336320 }
337321 else
338322 {
353337 }
354338
355339 gchar *
356 get_human_size (guint size, gboolean with_space)
340 get_human_size (gint64 size, gboolean with_space)
357341 {
358342 gchar *label = malloc (LABEL_MAX);
359343 gchar *space = with_space ? " " : "";
360344
361 if (size < KIB)
362 {
363 snprintf (label, LABEL_MAX, "%d%sB", size, space);
345 if (size < 0)
346 {
347 *label = 0;
348 }
349 else if (size < KIB)
350 {
351 snprintf (label, LABEL_MAX, "%" PRId64 "%sB", size, space);
364352 }
365353 else if (size < KIB * KIB)
366354 {
380368 return label;
381369 }
382370
371 static inline void
372 set_job_control_progress_value (struct job_control *control, gdouble p)
373 {
374 control->progress =
375 (control->part / (double) control->parts) + (p / (double) control->parts);
376 }
377
383378 void
384379 set_job_control_progress (struct job_control *control, gdouble p)
385380 {
386 gdouble v = (double) control->part / control->parts + p / control->parts;
387 control->callback (v);
388 }
389
390 gint
391 load_device_desc (struct connector_device_desc *device_desc, guint8 id,
392 const char *devices_filename_)
393 {
394 gint err, devices;
395 JsonParser *parser;
396 JsonReader *reader;
397 gchar *devices_filename;
398 GError *error = NULL;
399
400 parser = json_parser_new ();
401
402 if (devices_filename_)
403 {
404 devices_filename = strdup (devices_filename_);
405
406 if (!json_parser_load_from_file (parser, devices_filename, &error))
407 {
408 error_print ("%s", error->message);
409 g_clear_error (&error);
410 err = -ENODEV;
411 goto cleanup_parser;
412 }
413 }
414 else
415 {
416 devices_filename = get_expanded_dir (CONF_DIR DEVICES_FILE);
417
418 if (!json_parser_load_from_file (parser, devices_filename, &error))
419 {
420 debug_print (1, "%s\n", error->message);
421 g_clear_error (&error);
422
423 g_free (devices_filename);
424 devices_filename = strdup (DATADIR DEVICES_FILE);
425
426 debug_print (1, "Falling back to %s...\n", devices_filename);
427
428 if (!json_parser_load_from_file (parser, devices_filename, &error))
429 {
430 error_print ("%s", error->message);
431 g_clear_error (&error);
432 err = -ENODEV;
433 goto cleanup_parser;
434 }
435 }
436 }
437
438 reader = json_reader_new (json_parser_get_root (parser));
439 if (!reader)
440 {
441 error_print ("Unable to read from parser");
442 err = -ENODEV;
443 goto cleanup_parser;
444 }
445
446 if (!json_reader_is_array (reader))
447 {
448 error_print ("Not an array\n");
449 err = -ENODEV;
450 goto cleanup_reader;
451 }
452
453 devices = json_reader_count_elements (reader);
454 if (!devices)
455 {
456 debug_print (1, "No devices found\n");
457 err = -ENODEV;
458 goto cleanup_reader;
459 }
460
461 err = -ENODEV;
462 for (int i = 0; i < devices; i++)
463 {
464 if (!json_reader_read_element (reader, i))
465 {
466 error_print ("Cannot read element %d. Continuing...\n", i);
467 continue;
468 }
469
470 if (!json_reader_read_member (reader, DEV_TAG_ID))
471 {
472 error_print ("Cannot read member '%s'. Continuing...\n",
473 DEV_TAG_ID);
474 continue;
475 }
476 device_desc->id = json_reader_get_int_value (reader);
477 json_reader_end_member (reader);
478
479 if (device_desc->id != id)
480 {
481 json_reader_end_element (reader);
482 continue;
483 }
484
485 err = 0;
486 debug_print (1, "Device %d found\n", id);
487
488 if (!json_reader_read_member (reader, DEV_TAG_NAME))
489 {
490 error_print ("Cannot read member '%s'. Stopping...\n",
491 DEV_TAG_NAME);
492 json_reader_end_element (reader);
493 err = -ENODEV;
494 break;
495 }
496 device_desc->name = strdup (json_reader_get_string_value (reader));
497 json_reader_end_member (reader);
498
499 if (!json_reader_read_member (reader, DEV_TAG_ALIAS))
500 {
501 error_print ("Cannot read member '%s'. Stopping...\n",
502 DEV_TAG_ALIAS);
503 json_reader_end_element (reader);
504 err = -ENODEV;
505 break;
506 }
507 device_desc->alias = strdup (json_reader_get_string_value (reader));
508 json_reader_end_member (reader);
509
510 if (!json_reader_read_member (reader, DEV_TAG_FILESYSTEMS))
511 {
512 error_print ("Cannot read member '%s'. Stopping...\n",
513 DEV_TAG_FILESYSTEMS);
514 json_reader_end_element (reader);
515 err = -ENODEV;
516 break;
517 }
518 device_desc->filesystems = json_reader_get_int_value (reader);
519 json_reader_end_member (reader);
520
521 if (!json_reader_read_member (reader, DEV_TAG_STORAGE))
522 {
523 error_print ("Cannot read member '%s'. Stopping...\n",
524 DEV_TAG_STORAGE);
525 json_reader_end_element (reader);
526 err = -ENODEV;
527 break;
528 }
529 device_desc->storage = json_reader_get_int_value (reader);
530 json_reader_end_member (reader);
531
532 break;
533 }
534
535 cleanup_reader:
536 g_object_unref (reader);
537 cleanup_parser:
538 g_object_unref (parser);
539 g_free (devices_filename);
540 return err;
541 }
381 g_mutex_lock (&control->mutex);
382 set_job_control_progress_value (control, p);
383 g_mutex_unlock (&control->mutex);
384
385 if (control->callback)
386 {
387 control->callback (control);
388 }
389 }
390
391 void
392 set_job_control_progress_no_sync (struct job_control *control, gdouble p)
393 {
394 set_job_control_progress_value (control, p);
395
396 if (control->callback)
397 {
398 control->callback (control);
399 }
400 }
401
402 gboolean
403 file_matches_extensions (const gchar * name, gchar ** extensions)
404 {
405 const gchar *extension;
406 gchar **e = extensions;
407
408 if (!e)
409 {
410 return TRUE;
411 }
412
413 extension = get_ext (name);
414 if (!extension)
415 {
416 return FALSE;
417 }
418
419 while (*e)
420 {
421 if (!strcasecmp (extension, *e))
422 {
423 return TRUE;
424 }
425 e++;
426 }
427
428 return FALSE;
429 }
430
431 gboolean
432 iter_matches_extensions (struct item_iterator *iter, gchar ** extensions)
433 {
434 if (iter->item.type == ELEKTROID_DIR)
435 {
436 return TRUE;
437 }
438
439 return file_matches_extensions (iter->item.name, extensions);
440 }
2424 #include <unistd.h>
2525 #include <glib.h>
2626 #include <json-glib/json-glib.h>
27 #include <inttypes.h>
2728 #include "../config.h"
2829
2930 #define CONF_DIR "~/.config/" PACKAGE
3031
31 #define LABEL_MAX 128
32
33 #define ELEKTRON_LOOP_TYPE 0x7f
34 #define ELEKTRON_SAMPLE_RATE 48000
32 #define LABEL_MAX 256
33
34 #define AUDIO_SAMPLE_RATE 48000
35
36 #define MAX_BACKEND_FSS (sizeof (gint32) * 8)
37 #define MAX_BACKEND_STORAGE MAX_BACKEND_FSS
3538
3639 #define debug_print(level, format, ...) if (level <= debug_level) fprintf(stderr, "DEBUG:" __FILE__ ":%d:(%s): " format, __LINE__, __FUNCTION__, ## __VA_ARGS__)
3740 #define error_print(format, ...) fprintf(stderr, "%sERROR:" __FILE__ ":%d:(%s): " format "%s", isatty(fileno(stderr)) ? "\x1b[31m" : "", __LINE__, __FUNCTION__, ## __VA_ARGS__, isatty(fileno(stderr)) ? "\x1b[m" : "")
4346 ELEKTROID_DIR = 'D'
4447 };
4548
49 struct backend;
50
4651 struct item_iterator;
4752
4853 typedef guint (*iterator_next) (struct item_iterator *);
4954
5055 typedef void (*iterator_free) (void *);
5156
52 typedef gint (*iterator_copy) (struct item_iterator *,
53 struct item_iterator *, gboolean);
57 typedef gint (*iterator_copy) (struct item_iterator *, struct item_iterator *,
58 gboolean);
59
60 //name must be filled up always. If no name is available, this can be a string representation of the ID without padding. See set_item_name_from_id function.
61 //In slot mode, id needs to be filled up and will typically be the MIDI preset number (the id is the filename).
62 //In default mode (not slot mode), id can be used for any or no purpose. It's still possible to use the id as the filename by using the FS_OPTION_ID_AS_FILENAME option.
63 //A value of -1 in size will show nothing on the interface. If the size column is not used at all, use FS_OPTION_SHOW_SIZE_COLUMN.
5464
5565 struct item
5666 {
57 gchar *name;
58 guint32 size;
59 gint32 index;
6067 enum item_type type;
68 gchar name[LABEL_MAX];
69 gint32 id;
70 gint64 size;
6171 };
6272
6373 struct item_iterator
6474 {
6575 iterator_next next;
6676 iterator_free free;
77 //copy is only needed when the FS supports directories. This does not mean that mkdir is supported, as dirs could be just a way to show the data.
6778 iterator_copy copy;
6879 void *data;
6980 struct item item;
7081 };
7182
72 typedef void (*job_control_callback) (gdouble);
83 typedef void (*fs_print_item) (struct item_iterator *, struct backend *);
84
85 struct job_control;
86
87 typedef void (*job_control_callback) (struct job_control *);
7388
7489 struct job_control
7590 {
7893 job_control_callback callback;
7994 gint parts;
8095 gint part;
96 gdouble progress;
8197 void *data;
8298 };
8399
84 struct sample_loop_data
85 {
86 gint32 start;
87 gint32 end;
88 };
89
90 typedef gint (*fs_init_iter_func) (struct item_iterator *, const gchar *,
91 void *);
92
93 typedef gint (*fs_path_func) (const gchar *, void *);
94
95 typedef gint (*fs_src_dst_func) (const gchar *, const gchar *, void *);
96
97 typedef gint (*fs_remote_file_op) (const gchar *, GByteArray *,
98 struct job_control *, void *);
99
100 typedef gchar *(*fs_get_item_id) (struct item *);
100 // This contains information taken from from the sample data.
101 struct sample_info
102 {
103 guint32 loopstart;
104 guint32 loopend;
105 guint32 looptype;
106 guint32 samplerate;
107 guint32 bitdepth;
108 guint32 channels;
109 guint32 frames;
110 };
111
112 // This contains the format in which data must be load.
113 struct sample_params
114 {
115 guint32 channels;
116 guint32 samplerate;
117 };
118
119 struct device_desc
120 {
121 guint32 id;
122 gchar name[LABEL_MAX];
123 gchar alias[LABEL_MAX];
124 guint32 filesystems;
125 guint32 storage;
126 };
127
128 enum sysex_transfer_status
129 {
130 WAITING,
131 SENDING,
132 RECEIVING,
133 FINISHED
134 };
135
136 struct sysex_transfer
137 {
138 gboolean active;
139 GMutex mutex;
140 enum sysex_transfer_status status;
141 gint timeout; //Measured in ms. -1 is infinite.
142 gint time;
143 gboolean batch;
144 GByteArray *raw;
145 gint err;
146 };
147
148 struct fs_operations;
149
150 typedef gint (*fs_init_iter_func) (struct backend *, struct item_iterator *,
151 const gchar *);
152
153 typedef gint (*fs_path_func) (struct backend *, const gchar *);
154
155 typedef gint (*fs_src_dst_func) (struct backend *, const gchar *,
156 const gchar *);
157
158 typedef gint (*fs_remote_file_op) (struct backend *, const gchar *,
159 GByteArray *, struct job_control *);
160
161 typedef gchar *(*fs_get_item_slot) (struct item *, struct backend *);
101162
102163 typedef gint (*fs_local_file_op) (const gchar *, GByteArray *,
103164 struct job_control *);
104165
166 typedef gchar *(*fs_get_ext) (const struct device_desc *,
167 const struct fs_operations *);
168
169 typedef gchar *(*t_get_upload_path) (struct backend *, struct item_iterator *,
170 const struct fs_operations *,
171 const gchar *, const gchar *, gint32 *);
172
173 typedef gchar *(*t_get_download_path) (struct backend *,
174 struct item_iterator *,
175 const struct fs_operations *,
176 const gchar *, const gchar *);
177
178 typedef gint (*t_sysex_transfer) (struct backend *, struct sysex_transfer *);
179
180 // All the function members that return gint should return 0 if no error and a negative number in case of error.
181 // errno values are recommended as will provide the user with a meaningful message. In particular,
182 // ENOSYS could be used when a particular device does not support a feature that other devices implementing the same filesystem do.
183
184 // rename and move are different operations. If move is implemented, rename must behave the same way. However, t's perfectly
185 // possible to implement rename without implementing move. This is the case in slot mode filesystems.
186
105187 struct fs_operations
106188 {
107 gint fs;
189 gint32 fs;
190 guint32 options;
191 const gchar *name;
192 const gchar *gui_name;
193 const gchar *gui_icon;
194 const gchar *type_ext;
195 guint32 max_name_len;
108196 fs_init_iter_func readdir;
197 fs_print_item print_item;
109198 fs_path_func mkdir;
110199 fs_path_func delete;
111200 fs_src_dst_func rename;
115204 fs_src_dst_func swap;
116205 fs_remote_file_op download;
117206 fs_remote_file_op upload;
118 fs_get_item_id getid;
207 fs_get_item_slot get_slot;
119208 fs_local_file_op save;
120209 fs_local_file_op load;
121 const gchar *extension;
122 };
123
124 struct connector_device_desc
125 {
126 guint32 id;
127 gchar *name;
128 gchar *alias;
129 guint8 filesystems;
130 guint8 storage;
210 fs_get_ext get_ext;
211 t_get_upload_path get_upload_path;
212 t_get_download_path get_download_path;
213 };
214
215 enum fs_options
216 {
217 //Show the audio player.
218 FS_OPTION_AUDIO_PLAYER = 0x1,
219 //Allow stereo samples. Only useful if used together with FS_OPTION_AUDIO_PLAYER
220 FS_OPTION_STEREO = 0x2,
221 //Every operation will block the remote browser.
222 FS_OPTION_SINGLE_OP = 0x4,
223 //Filename is the ID instead of the name. Useful when the device allows different items to have the same name.
224 FS_OPTION_ID_AS_FILENAME = 0x8,
225 //In slot mode, dst_dir passed to t_get_upload_path includes the ID, a colon (':') and the system filename.
226 //Also, as every destination slot is always used, drop is only possible over a concrete slot.
227 //A DND operation of several items over a slot will behave as dropping the first item over the destination slot and the rest over the following ones.
228 //Typically used together with FS_OPTION_ID_AS_FILENAME but not necessary.
229 FS_OPTION_SLOT_STORAGE = 0x10,
230 //Show column options. Name column is always showed.
231 FS_OPTION_SHOW_ID_COLUMN = 0x20,
232 FS_OPTION_SHOW_SIZE_COLUMN = 0x40,
233 FS_OPTION_SHOW_SLOT_COLUMN = 0x80,
234 //Sort items options.
235 FS_OPTION_SORT_BY_ID = 0x100,
236 FS_OPTION_SORT_BY_NAME = 0x200
131237 };
132238
133239 extern int debug_level;
144250
145251 gchar get_type_from_inventory_icon (const gchar *);
146252
147 gchar *get_expanded_dir (const char *);
253 gchar *get_expanded_dir (const gchar *);
148254
149255 gchar *get_local_startup_path (const gchar *);
150256
151257 void free_msg (gpointer);
152258
153 gchar *get_item_name (struct item *);
154
155 gchar *get_item_index (struct item *);
259 /**
260 * Returns the filename for an item, which is a string that uniquely idenfifies an item.
261 * In a PC, filenames are typically strings but in embedded devices this could be just a number (in string format).
262 * Typically, in these systems, several slots can have the same name but the id is an address to a memory slot.
263 * @param options The options member in the fs_operations struct.
264 * @param item
265 */
266 gchar *get_filename (guint32 options, struct item *item);
156267
157268 guint next_item_iterator (struct item_iterator *);
158269
167278
168279 gint save_file_char (const gchar *, const guint8 *, ssize_t);
169280
170 gchar *get_human_size (guint, gboolean);
281 gchar *get_human_size (gint64, gboolean);
171282
172283 void set_job_control_progress (struct job_control *, gdouble);
173284
174 gint load_device_desc (struct connector_device_desc *, guint8, const char *);
285 void set_job_control_progress_no_sync (struct job_control *, gdouble);
286
287 gboolean file_matches_extensions (const gchar *, gchar **);
288
289 gboolean iter_matches_extensions (struct item_iterator *, gchar **);
175290
176291 #endif
0 TESTS = sample_fs_tests.sh data_fs_tests.sh
0 TESTS = test.sh
11
22 EXTRA_DIST = \
33 $(TESTS) \
44 res/square.wav \
55 res/square_loop.wav \
66 res/SOUND.dtdata \
7 res/devices.json
7 res/devices.json \
8 res/sequence.mbseq \
9 res/sequence_back.mbseq
810
911 AM_TESTS_ENVIRONMENT = \
10 ecli='$(abs_top_builddir)/src/elektroid-cli -f $(srcdir)/res/devices.json'; \
12 ecli='$(abs_top_builddir)/src/elektroid-cli'; \
1113 export ecli;
0 #!/usr/bin/env bash
1
2 #There are different files because of the ID stored in them.
3 #We overwrite these IDs while uploading but it's easier to have different files to run cksum on them.
4
5 PANEL_SRC_FILE="$srcdir/res/CZ-101 panel src.syx"
6 INTERNAL_SRC_FILE="$srcdir/res/CZ-101 internal 01 src.syx"
7 PANEL_FILE="CZ-101 panel.syx"
8 PRESET_FILE="CZ-101 preset 01.syx"
9 INTERNAL_FILE="CZ-101 internal 01.syx"
10 INTERNAL_FILE_BACKUP="CZ-101 internal 01 backup.syx"
11
12 function exitWithError() {
13 echo "Restoring..."
14 $ecli cz-program-ul "$INTERNAL_FILE_BACKUP" $TEST_DEVICE:/internal/1:foo
15 rm -f "$PANEL_FILE" "$PRESET_FILE" "$INTERNAL_FILE" "$INTERNAL_FILE_BACKUP"
16 exit $1
17 }
18
19 echo "Testing ls..."
20 files=$($ecli cz-program-ls $TEST_DEVICE:/)
21 [ $? -ne 0 ] && exit 1
22 expected="D -1B preset
23 D -1B internal
24 F 264B panel"
25 [ "$files" != "$expected" ] && echo "Tests will fail with a cartridge inserted" && exit 1
26
27 echo "Testing internal download..."
28 $ecli cz-program-download $TEST_DEVICE:/internal/1 # No name is allowed in the CZ filesystem (slot mode)
29 [ $? -ne 0 ] && exit 1
30 [ ! -f "$INTERNAL_FILE" ] && exit 1
31 mv "$INTERNAL_FILE" "$INTERNAL_FILE_BACKUP"
32
33 echo "Testing upload bad file..."
34 $ecli cz-program-ul foo $TEST_DEVICE:/1:a
35 [ $? -eq 0 ] && exitWithError 1
36
37 echo "Testing upload bad destination..."
38 $ecli cz-program-ul foo $TEST_DEVICE:/1
39 [ $? -eq 0 ] && exitWithError 1
40
41 echo "Testing panel upload..."
42 $ecli cz-program-ul "$PANEL_SRC_FILE" $TEST_DEVICE:/panel:panel
43 [ $? -ne 0 ] && exitWithError 1
44
45 echo "Testing panel download..."
46 $ecli cz-program-download $TEST_DEVICE:/panel
47 [ $? -ne 0 ] && exitWithError 1
48 [ ! -f "$PANEL_FILE" ] && exitWithError 1
49 [ $(cksum "$PANEL_FILE" | awk '{print $1}') != $(cksum "$PANEL_SRC_FILE" | awk '{print $1}') ] && exitWithError 1
50
51 echo "Testing preset download..."
52 $ecli cz-program-download $TEST_DEVICE:/preset/1 # No name is allowed in the CZ filesystem (slot mode)
53 [ $? -ne 0 ] && exitWithError 1
54 [ ! -f "$PRESET_FILE" ] && exitWithError 1
55
56 echo "Testing internal upload..."
57 $ecli cz-program-ul "$INTERNAL_SRC_FILE" $TEST_DEVICE:/internal/1:bar
58 [ $? -ne 0 ] && exitWithError 1
59
60 $ecli cz-program-download $TEST_DEVICE:/internal/1
61 [ $? -ne 0 ] && exitWithError 1
62 [ $(cksum "$INTERNAL_FILE" | awk '{print $1}') != $(cksum "$INTERNAL_SRC_FILE" | awk '{print $1}') ] && exitWithError 1
63
64 exitWithError 0
+0
-98
test/data_fs_tests.sh less more
0 #!/usr/bin/env bash
1
2 function cleanupAndExitWithError () {
3 $ecli cl-data $DEVICE:/soundbanks/H/1
4 $ecli cl-data $DEVICE:/soundbanks/H/62
5 $ecli cl-data $DEVICE:/soundbanks/H/63
6 $ecli cl-data $DEVICE:/soundbanks/H/64
7 $ecli cl-data $DEVICE:/soundbanks/H/256
8 exit 1
9 }
10
11 function get_sound_n_with_id () {
12 s="sound$1"
13 echo "${!s}" | sed "s/^F $1 0012/F $2 007e/"
14 }
15
16 echo "Getting devices..."
17 DEVICE=$($ecli ld | head -n 1 | awk '{print $1}')
18 [ -z "$DEVICE" ] && echo "No device found" && exit 0
19 echo "Using device $DEVICE..."
20
21 sound1=$($ecli ls-data $DEVICE:/soundbanks/A | grep "^F 1")
22 nsound1=$(get_sound_n_with_id 1 64)
23
24 sound2=$($ecli ls-data $DEVICE:/soundbanks/A | grep "^F 2")
25
26 echo "Testing data copy..."
27 $ecli cp-data $DEVICE:/soundbanks/A/1 $DEVICE:/soundbanks/H/64
28 [ $? -ne 0 ] && cleanupAndExitWithError
29 $ecli cp-data $DEVICE:/soundbanks/A/2 $DEVICE:/soundbanks/H/63
30 [ $? -ne 0 ] && cleanupAndExitWithError
31 output=$($ecli ls-data $DEVICE:/soundbanks/H)
32 actual=$(echo "$output" | grep "^F 64")
33 expected=$(get_sound_n_with_id 1 64)
34 [ "$actual" != "$expected" ] && cleanupAndExitWithError
35 actual=$(echo "$output" | grep "^F 63")
36 expected=$(get_sound_n_with_id 2 63)
37 [ "$actual" != "$expected" ] && cleanupAndExitWithError
38
39 echo "Testing data move..."
40 $ecli mv-data $DEVICE:/soundbanks/H/64 $DEVICE:/soundbanks/H/62
41 [ $? -ne 0 ] && cleanupAndExitWithError
42 output=$($ecli ls-data $DEVICE:/soundbanks/H)
43 actual=$(echo "$output" | grep "^F 62")
44 expected=$(get_sound_n_with_id 1 62)
45 [ "$actual" != "$expected" ] && cleanupAndExitWithError
46 actual=$(echo "$output" | grep "^F 64")
47 [ -n "$actual" ] && cleanupAndExitWithError
48
49 echo "Testing data swap..."
50 $ecli sw-data $DEVICE:/soundbanks/H/62 $DEVICE:/soundbanks/H/63
51 [ $? -ne 0 ] && cleanupAndExitWithError
52 output=$($ecli ls-data $DEVICE:/soundbanks/H)
53 actual=$(echo "$output" | grep "^F 62")
54 expected=$(get_sound_n_with_id 2 62)
55 [ "$actual" != "$expected" ] && cleanupAndExitWithError
56 actual=$(echo "$output" | grep "^F 63")
57 expected=$(get_sound_n_with_id 1 63)
58 [ "$actual" != "$expected" ] && cleanupAndExitWithError
59
60 echo "Testing data clear..."
61 $ecli cl-data $DEVICE:/soundbanks/H/63
62 [ $? -ne 0 ] && cleanupAndExitWithError
63 $ecli cl-data $DEVICE:/soundbanks/H/62
64 [ $? -ne 0 ] && cleanupAndExitWithError
65 output=$($ecli ls-data $DEVICE:/soundbanks/H)
66 [ $(echo "$output" | grep "^F 62" | wc -l) -ne 0 ] && cleanupAndExitWithError
67 [ $(echo "$output" | grep "^F 63" | wc -l) -ne 0 ] && cleanupAndExitWithError
68
69 echo "Testing upload..."
70 $ecli ul-data $srcdir/res/SOUND.dtdata $DEVICE:/soundbanks/H
71 [ $? -ne 0 ] && cleanupAndExitWithError
72 id=$($ecli ls-data $DEVICE:/soundbanks/H | grep 'SOUND$' | awk '{print $2}')
73
74 echo "Testing download..."
75 $ecli dl-data $DEVICE:/soundbanks/H/$id
76 [ $? -ne 0 ] && cleanupAndExitWithError
77 ls "SOUND.dtdata"
78 cksum SOUND.dtdata
79 cksum $srcdir/res/SOUND.dtdata
80 actual_cksum="$(cksum SOUND.dtdata | awk '{print $1}')"
81 [ "$actual_cksum" != "$(cksum $srcdir/res/SOUND.dtdata | awk '{print $1}')" ] && cleanupAndExitWithError
82 rm SOUND.dtdata
83 [ $? -ne 0 ] && cleanupAndExitWithError
84 $ecli cl-data $DEVICE:/soundbanks/H/$id
85 [ $? -ne 0 ] && cleanupAndExitWithError
86
87 echo "Testing upload..."
88 $ecli ul-data $srcdir/res/SOUND.dtdata $DEVICE:/soundbanks/H/256
89 [ $? -ne 0 ] && cleanupAndExitWithError
90 id=$($ecli ls-data $DEVICE:/soundbanks/H | grep 'SOUND$' | awk '{print $2}')
91 [ $id != 256 ] && cleanupAndExitWithError
92
93 echo "Testing data clear..."
94 $ecli cl-data $DEVICE:/soundbanks/H/256
95 [ $? -ne 0 ] && cleanupAndExitWithError
96
97 exit 0
0 #!/usr/bin/env bash
1
2 TEST_PRESET=99
3
4 function exitWithError() {
5 echo "Restoring preset..."
6 $ecli efactor-preset-ul "$f" $TEST_DEVICE:/$TEST_PRESET
7 rm "$f"
8 exit $1
9 }
10
11 echo "Using device $TEST_DEVICE..."
12
13 echo "Backing up preset..."
14 $ecli efactor-preset-dl $TEST_DEVICE:/$TEST_PRESET
15 f=$(echo Eventide\ Factor\ *)
16
17 echo "Testing ls..."
18 files=$($ecli efactor-preset-ls $TEST_DEVICE:/)
19 [ $? -ne 0 ] && exitWithError 1
20
21 echo "Testing upload..."
22 $ecli efactor-preset-ul "$srcdir/res/Eventide Factor Preset.syx" $TEST_DEVICE:/$TEST_PRESET
23 [ $? -ne 0 ] && exitWithError 1
24
25 #Uploading with name makes no sense for factor pedals as the file includes the name.
26
27 echo "Testing mv..."
28 $ecli efactor-preset-mv $TEST_DEVICE:/$TEST_PRESET "New Name"
29 [ $? -ne 0 ] && exitWithError 1
30
31 echo "Testing download..."
32 $ecli efactor-preset-dl $TEST_DEVICE:/$TEST_PRESET
33 [ $? -ne 0 ] && exitWithError 1
34 actual_cksum="$(cksum "Eventide Factor New Name.syx" | awk '{print $1}')"
35 rm "Eventide Factor New Name.syx"
36 echo $actual_cksum | awk '{print $1}'
37 cksum "$srcdir/res/Eventide Factor New Name.syx"
38 [ "$actual_cksum" != $(cksum "$srcdir/res/Eventide Factor New Name.syx" | awk '{print $1}') ] && exitWithError 1
39
40 exitWithError 0
0 #!/usr/bin/env bash
1
2 export ELEKTROID_ELEKTRON_JSON=$srcdir/res/devices.json
3
4 function cleanupAndExitWithError () {
5 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/1
6 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/62
7 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/63
8 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/64
9 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/256
10 exit 1
11 }
12
13 function get_sound_n_with_id () {
14 s="sound$1"
15 echo "${!s}" | sed "s/^F $1 0012/F $2 007e/"
16 }
17
18 echo "Using device $TEST_DEVICE..."
19
20 sound1=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/A | grep "^F 1")
21 nsound1=$(get_sound_n_with_id 1 64)
22
23 sound2=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/A | grep "^F 2")
24
25 echo "Testing data copy..."
26 $ecli elektron-data-cp $TEST_DEVICE:/soundbanks/A/1 $TEST_DEVICE:/soundbanks/H/64
27 [ $? -ne 0 ] && cleanupAndExitWithError
28 $ecli elektron-data-cp $TEST_DEVICE:/soundbanks/A/2 $TEST_DEVICE:/soundbanks/H/63
29 [ $? -ne 0 ] && cleanupAndExitWithError
30 output=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H)
31 actual=$(echo "$output" | grep "^F 64")
32 expected=$(get_sound_n_with_id 1 64)
33 [ "$actual" != "$expected" ] && cleanupAndExitWithError
34 actual=$(echo "$output" | grep "^F 63")
35 expected=$(get_sound_n_with_id 2 63)
36 [ "$actual" != "$expected" ] && cleanupAndExitWithError
37
38 echo "Testing data move..."
39 $ecli elektron-data-mv $TEST_DEVICE:/soundbanks/H/64 $TEST_DEVICE:/soundbanks/H/62
40 [ $? -ne 0 ] && cleanupAndExitWithError
41 output=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H)
42 actual=$(echo "$output" | grep "^F 62")
43 expected=$(get_sound_n_with_id 1 62)
44 [ "$actual" != "$expected" ] && cleanupAndExitWithError
45 actual=$(echo "$output" | grep "^F 64")
46 [ -n "$actual" ] && cleanupAndExitWithError
47
48 echo "Testing data swap..."
49 $ecli elektron-data-sw $TEST_DEVICE:/soundbanks/H/62 $TEST_DEVICE:/soundbanks/H/63
50 [ $? -ne 0 ] && cleanupAndExitWithError
51 output=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H)
52 actual=$(echo "$output" | grep "^F 62")
53 expected=$(get_sound_n_with_id 2 62)
54 [ "$actual" != "$expected" ] && cleanupAndExitWithError
55 actual=$(echo "$output" | grep "^F 63")
56 expected=$(get_sound_n_with_id 1 63)
57 [ "$actual" != "$expected" ] && cleanupAndExitWithError
58
59 echo "Testing data clear..."
60 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/63
61 [ $? -ne 0 ] && cleanupAndExitWithError
62 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/62
63 [ $? -ne 0 ] && cleanupAndExitWithError
64 output=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H)
65 [ $(echo "$output" | grep "^F 62" | wc -l) -ne 0 ] && cleanupAndExitWithError
66 [ $(echo "$output" | grep "^F 63" | wc -l) -ne 0 ] && cleanupAndExitWithError
67
68 echo "Testing upload..."
69 $ecli elektron-data-ul $srcdir/res/SOUND.dtdata $TEST_DEVICE:/soundbanks/H
70 [ $? -ne 0 ] && cleanupAndExitWithError
71 id=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H | grep 'SOUND$' | awk '{print $2}')
72
73 echo "Testing download..."
74 $ecli elektron-data-dl $TEST_DEVICE:/soundbanks/H/$id
75 [ $? -ne 0 ] && cleanupAndExitWithError
76 ls "SOUND.dtdata"
77 cksum SOUND.dtdata
78 cksum $srcdir/res/SOUND.dtdata
79 actual_cksum="$(cksum SOUND.dtdata | awk '{print $1}')"
80 [ "$actual_cksum" != "$(cksum $srcdir/res/SOUND.dtdata | awk '{print $1}')" ] && cleanupAndExitWithError
81 rm SOUND.dtdata
82 [ $? -ne 0 ] && cleanupAndExitWithError
83 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/$id
84 [ $? -ne 0 ] && cleanupAndExitWithError
85
86 echo "Testing upload..."
87 $ecli elektron-data-ul $srcdir/res/SOUND.dtdata $TEST_DEVICE:/soundbanks/H/256
88 [ $? -ne 0 ] && cleanupAndExitWithError
89 id=$($ecli elektron-data-ls $TEST_DEVICE:/soundbanks/H | grep 'SOUND$' | awk '{print $2}')
90 [ $id != 256 ] && cleanupAndExitWithError
91
92 echo "Testing data clear..."
93 $ecli elektron-data-cl $TEST_DEVICE:/soundbanks/H/256
94 [ $? -ne 0 ] && cleanupAndExitWithError
95
96 exit 0
0 #!/usr/bin/env bash
1
2 export ELEKTROID_ELEKTRON_JSON=$srcdir/res/devices.json
3
4 TEST_NAME=auto-test
5
6 echo "Using device $TEST_DEVICE..."
7
8 echo "Testing info..."
9 $ecli info $TEST_DEVICE:/
10 [ $? -ne 0 ] && exit 1
11
12 echo "Testing df..."
13 $ecli df $TEST_DEVICE:/
14 [ $? -ne 0 ] && exit 1
15
16 echo "Testing ls..."
17 $ecli elektron-sample-ls $TEST_DEVICE:/
18 [ $? -ne 0 ] && exit 1
19
20 echo "Testing mkdir..."
21 $ecli elektron-sample-mkdir $TEST_DEVICE:/$TEST_NAME
22 [ $? -ne 0 ] && exit 1
23
24 $ecli elektron-sample-ls $TEST_DEVICE:/$TEST_NAME
25 [ $? -ne 0 ] && exit 1
26
27 echo "Testing upload..."
28 $ecli elektron-sample-ul $srcdir/res/square.wav $TEST_DEVICE:/$TEST_NAME
29 [ $? -ne 0 ] && exit 1
30
31 echo "Testing upload (loop)..."
32 $ecli elektron-sample-ul $srcdir/res/square_loop.wav $TEST_DEVICE:/$TEST_NAME
33 [ $? -ne 0 ] && exit 1
34
35 output=$($ecli elektron-sample-ls $TEST_DEVICE:/$TEST_NAME)
36 type=$(echo "$output" | head -n 1 | awk '{print $1}')
37 size=$(echo "$output" | head -n 1 | awk '{print $2}')
38 name=$(echo "$output" | head -n 1 | awk '{print $4}')
39 [ "$type" != "F" ] || [ "$size" != "93.81KiB" ] || [ "$name" != "square" ] && exit 1
40
41 echo "Testing upload (nonexistent source)..."
42 $ecli elektron-sample-upload $srcdir/res/foo $TEST_DEVICE:/$TEST_NAME
43 [ $? -eq 0 ] && exit 1
44
45 echo "Testing download..."
46 $ecli elektron-sample-download $TEST_DEVICE:/$TEST_NAME/square
47 [ $? -ne 0 ] && exit 1
48 actual_cksum="$(cksum square.wav | awk '{print $1}')"
49 rm square.wav
50 [ "$actual_cksum" != "$(cksum $srcdir/res/square.wav | awk '{print $1}')" ] && exit 1
51
52 echo "Testing download (loop)..."
53 $ecli elektron-sample-dl $TEST_DEVICE:/$TEST_NAME/square_loop
54 [ $? -ne 0 ] && exit 1
55 actual_cksum="$(cksum square_loop.wav | awk '{print $1}')"
56 rm square_loop.wav
57 [ "$actual_cksum" != "$(cksum $srcdir/res/square_loop.wav | awk '{print $1}')" ] && exit 1
58
59 echo "Testing download (nonexistent source)..."
60 $ecli elektron-sample-dl $TEST_DEVICE:/$TEST_NAME/foo
61 [ $? -eq 0 ] && exit 1
62
63 echo "Testing mv..."
64 $ecli elektron-sample-mv $TEST_DEVICE:/$TEST_NAME/square $TEST_DEVICE:/$TEST_NAME/sample
65 [ $? -ne 0 ] && exit 1
66
67 echo "Testing mv..."
68 $ecli elektron-sample-mv $TEST_DEVICE:/$TEST_NAME/foo $TEST_DEVICE:/$TEST_NAME/sample
69 [ $? -eq 0 ] && exit 1
70
71 echo "Testing rm..."
72 $ecli elektron-sample-rm $TEST_DEVICE:/$TEST_NAME/sample
73 [ $? -ne 0 ] && exit 1
74
75 echo "Testing rm (nonexistent file)..."
76 $ecli elektron-sample-rm $TEST_DEVICE:/$TEST_NAME/sample
77 [ $? -eq 0 ] && exit 1
78
79 echo "Testing rmdir..."
80 $ecli elektron-sample-rmdir $TEST_DEVICE:/$TEST_NAME
81 [ $? -ne 0 ] && exit 1
82
83 echo "Testing rmdir (nonexistent dir)..."
84 $ecli elektron-sample-rmdir $TEST_DEVICE:/$TEST_NAME
85 [ $? -eq 0 ] && exit 1
86
87 echo "Testing recursive mkdir..."
88 $ecli elektron-sample-mkdir $TEST_DEVICE:/$TEST_NAME/foo
89 [ $? -ne 0 ] && exit 1
90
91 echo "Testing recursive rmdir..."
92 $ecli elektron-sample-rmdir $TEST_DEVICE:/$TEST_NAME
93 [ $? -ne 0 ] && exit 1
94
95 echo "Testing ls (nonexistent dir)..."
96 $ecli elektron-sample-ls $TEST_DEVICE:/$TEST_NAME
97 [ $? -eq 0 ] && exit 1
98
99 echo "Testing ls (nonexistent dir inside nonexistent dir)..."
100 $ecli elektron-sample-ls $TEST_DEVICE:/$TEST_NAME/foo
101 [ $? -eq 0 ] && exit 1
102
103 exit 0
0 #!/usr/bin/env bash
1
2 SEQ_FILE="MicroBrute sequence 1.mbseq"
3 SEQ_FILE_BACKUP="backup.mbseq"
4 SEQ_FILE_TEST="$srcdir/res/sequence.mbseq"
5 SEQ_FILE_TEST_BACK="$srcdir/res/sequence_back.mbseq"
6
7 function exitWithError() {
8 echo "Restoring..."
9 $ecli microbrute-sequence-upload "$SEQ_FILE_BACKUP" $TEST_DEVICE:/0:1
10 rm -f "$SEQ_FILE"
11 rm -f "$SEQ_FILE_BACKUP"
12 exit $1
13 }
14
15 echo "Using device $TEST_DEVICE..."
16
17 echo "Testing ls..."
18 $ecli microbrute-sequence-ls $TEST_DEVICE:/
19 files=$($ecli microbrute-sequence-ls $TEST_DEVICE:/ | wc -l)
20 [ $? -ne 0 ] && exit 1
21 [ $files -ne 8 ] && exit 1
22
23 echo "Testing download..."
24 $ecli microbrute-sequence-download $TEST_DEVICE:/0
25 [ $? -ne 0 ] && exit 1
26 [ ! -f "$SEQ_FILE" ] && exit 1
27 mv "$SEQ_FILE" "$SEQ_FILE_BACKUP"
28
29 echo "Testing upload bad file..."
30 $ecli microbrute-sequence-ul foo $TEST_DEVICE:/0:a
31 [ $? -eq 0 ] && exitWithError 1
32
33 echo "Testing upload bad destination..."
34 $ecli microbrute-sequence-ul foo $TEST_DEVICE:/9
35 [ $? -eq 0 ] && exitWithError 1
36
37 echo "Testing upload..."
38 $ecli microbrute-sequence-upload $SEQ_FILE_TEST $TEST_DEVICE:/0:1
39 [ $? -ne 0 ] && exitWithError 1
40
41 $ecli microbrute-sequence-dl $TEST_DEVICE:/0
42 [ $? -ne 0 ] && exitWithError 1
43 [ $(cksum "$SEQ_FILE" | awk '{print $1}') != $(cksum $SEQ_FILE_TEST_BACK | awk '{print $1}') ] && exitWithError 1
44
45 exitWithError 0
Binary diff not shown
0 1: 60 00 0 01 2xx 6200 000120 x12 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60
1 60
0 1:60 x x x x x x x 120 x 12 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60
Binary diff not shown
+0
-106
test/sample_fs_tests.sh less more
0 #!/usr/bin/env bash
1
2 TEST_NAME=auto-test
3
4 echo "Getting devices..."
5 DEVICE=$($ecli ld | head -n 1 | awk '{print $1}')
6 [ -z "$DEVICE" ] && echo "No device found" && exit 0
7 echo "Using device $DEVICE..."
8
9 echo "Testing info..."
10 $ecli info $DEVICE:/
11 [ $? -ne 0 ] && exit 1
12
13 echo "Testing df..."
14 $ecli df $DEVICE:/
15 [ $? -ne 0 ] && exit 1
16
17 echo "Testing ls..."
18 $ecli ls $DEVICE:/
19 [ $? -ne 0 ] && exit 1
20
21 echo "Testing mkdir..."
22 $ecli mkdir $DEVICE:/$TEST_NAME
23 [ $? -ne 0 ] && exit 1
24
25 $ecli ls $DEVICE:/$TEST_NAME
26 [ $? -ne 0 ] && exit 1
27
28 echo "Testing upload..."
29 $ecli ul-sample $srcdir/res/square.wav $DEVICE:/$TEST_NAME
30 [ $? -ne 0 ] && exit 1
31
32 echo "Testing upload (loop)..."
33 $ecli ul-sample $srcdir/res/square_loop.wav $DEVICE:/$TEST_NAME
34 [ $? -ne 0 ] && exit 1
35
36 output=$($ecli ls $DEVICE:/$TEST_NAME)
37 echo "$output"
38 type=$(echo "$output" | head -n 1 | awk '{print $1}')
39 size=$(echo "$output" | head -n 1 | awk '{print $2}')
40 name=$(echo "$output" | head -n 1 | awk '{print $4}')
41 [ "$type" != "F" ] || [ "$size" != "93.81KiB" ] || [ "$name" != "square" ] && exit 1
42
43 echo "Testing upload (nonexistent source)..."
44 $ecli ul-sample $srcdir/res/foo $DEVICE:/$TEST_NAME
45 [ $? -eq 0 ] && exit 1
46
47 echo "Testing download..."
48 $ecli -v download $DEVICE:/$TEST_NAME/square
49 [ $? -ne 0 ] && exit 1
50 actual_cksum="$(cksum square.wav | awk '{print $1}')"
51 rm square.wav
52 [ "$actual_cksum" != "$(cksum $srcdir/res/square.wav | awk '{print $1}')" ] && exit 1
53
54 echo "Testing download (loop)..."
55 $ecli -v dl-sample $DEVICE:/$TEST_NAME/square_loop
56 [ $? -ne 0 ] && exit 1
57 actual_cksum="$(cksum square_loop.wav | awk '{print $1}')"
58 rm square_loop.wav
59 [ "$actual_cksum" != "$(cksum $srcdir/res/square_loop.wav | awk '{print $1}')" ] && exit 1
60
61 echo "Testing download (nonexistent source)..."
62 $ecli dl-sample $DEVICE:/$TEST_NAME/foo
63 [ $? -eq 0 ] && exit 1
64
65 echo "Testing mv..."
66 $ecli mv $DEVICE:/$TEST_NAME/square $DEVICE:/$TEST_NAME/sample
67 [ $? -ne 0 ] && exit 1
68
69 echo "Testing mv..."
70 $ecli mv $DEVICE:/$TEST_NAME/foo $DEVICE:/$TEST_NAME/sample
71 [ $? -eq 0 ] && exit 1
72
73 echo "Testing rm..."
74 $ecli rm $DEVICE:/$TEST_NAME/sample
75 [ $? -ne 0 ] && exit 1
76
77 echo "Testing rm (nonexistent file)..."
78 $ecli rm $DEVICE:/$TEST_NAME/sample
79 [ $? -eq 0 ] && exit 1
80
81 echo "Testing rmdir..."
82 $ecli rmdir $DEVICE:/$TEST_NAME
83 [ $? -ne 0 ] && exit 1
84
85 echo "Testing rmdir (nonexistent dir)..."
86 $ecli rmdir $DEVICE:/$TEST_NAME
87 [ $? -eq 0 ] && exit 1
88
89 echo "Testing recursive mkdir..."
90 $ecli mkdir $DEVICE:/$TEST_NAME/foo
91 [ $? -ne 0 ] && exit 1
92
93 echo "Testing recursive rmdir..."
94 $ecli rmdir $DEVICE:/$TEST_NAME
95 [ $? -ne 0 ] && exit 1
96
97 echo "Testing ls (nonexistent dir)..."
98 $ecli ls $DEVICE:/$TEST_NAME
99 [ $? -eq 0 ] && exit 1
100
101 echo "Testing ls (nonexistent dir inside nonexistent dir)..."
102 $ecli ls $DEVICE:/$TEST_NAME/foo
103 [ $? -eq 0 ] && exit 1
104
105 exit 0
0 #!/usr/bin/env bash
1
2 echo "Using device $TEST_DEVICE..."
3
4 echo "Testing ls..."
5 files=$($ecli sds-mono16-ls $TEST_DEVICE:/)
6 [ $? -ne 0 ] && exit 1
7 echo "$files" | head
8 echo '[...]'
9 [ $(echo "$files" | wc -l) -ne 1000 ] && exit 1
10
11 echo "Testing upload..."
12 $ecli sds-mono16-ul $srcdir/res/silence.wav $TEST_DEVICE:/1
13 [ $? -ne 1 ] && exit 1
14
15 echo "Testing upload with name..."
16 $ecli sds-mono16-ul $srcdir/res/silence.wav $TEST_DEVICE:/1:silence
17 [ $? -ne 0 ] && exit 1
18
19 # If renaming is not implemented, this will fail.
20 echo "Testing mv..."
21 $ecli sds-mono16-ul $TEST_DEVICE:/1 "Foo"
22 [ $? -ne 1 ] && exit 1
23
24 echo "Testing download..."
25 $ecli sds-mono16-download $TEST_DEVICE:/1
26 [ $? -ne 0 ] && exit 1
27 actual_cksum="$(cksum 001.wav | awk '{print $1}')"
28 rm 001.wav
29 [ "$actual_cksum" != "$(cksum $srcdir/res/silence.wav | awk '{print $1}')" ] && exit 1
30
31 exit 0
0 #!/usr/bin/env bash
1
2 [ -z "$TEST_DEVICE" ] && echo "Environment variable TEST_DEVICE not set. Nothing to run." && exit 0
3 [ -z "$TEST_CONNECTOR_FILESYSTEM" ] && echo "Environment variable TEST_CONNECTOR_FILESYSTEM not set. Nothing to run." && exit 0
4
5 ./${TEST_CONNECTOR_FILESYSTEM}_fs_tests.sh
6
7 exit $?