Codebase list elektroid / 49fe91c
New upstream version 2.0 Dennis Braun 2 years ago
51 changed file(s) with 9365 addition(s) and 4122 deletion(s). Raw diff Collapse all Expand all
00 ACLOCAL_AMFLAGS=-I m4
1
2 if CLI_ONLY
3 SUBDIRS=src test man
4 else
15 SUBDIRS=src res test po man
6 endif
00 # Elektroid
11
2 Elektroid is a GNU/Linux sample 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, Digitakt and Analog Rytm mk1 and mk2.
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 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.
46
57 ## Installation
68
7 As with other autotools project, you need to run the following commands.
9 As with other autotools project, you need to run the following commands. If you just want to compile `elektroid-cli`, pass `CLI_ONLY=yes` to `/configure`.
810
911 ```
1012 autoreconf --install
1517
1618 The package dependencies for Debian based distributions are:
1719 - automake
20 - libtool
21 - build-essential
1822 - libasound2-dev
1923 - libgtk-3-dev
2024 - libpulse-dev
2125 - libsndfile1-dev
2226 - libsamplerate0-dev
23 - libtool
2427 - autopoint
2528 - gettext
2629 - zlib1g-dev
27
28 You can easily install them by running `sudo apt install automake libasound2-dev libgtk-3-dev libpulse-dev libsndfile1-dev libsamplerate0-dev libtool autopoint gettext zlib1g-dev`.
30 - libjson-glib-dev
31 - libzip-dev
32
33 You can easily install them by running `sudo apt install automake libtool build-essential libasound2-dev libgtk-3-dev libpulse-dev libsndfile1-dev libsamplerate0-dev autopoint gettext zlib1g-dev libjson-glib-dev libzip-dev`.
34
35 If you are only compiling the CLI, install the dependencies with `sudo apt install automake libtool build-essential libasound2-dev libglib2.0-dev libsndfile1-dev libsamplerate0-dev libtool zlib1g-dev libjson-glib-dev libzip-dev`.
2936
3037 ## CLI
3138
32 `elektroid-cli` provides the same funcionality than `elektroid`. Provided paths must always be prepended with the device id and a colon (':'), e.g. `0:/samples`.
33 Here are the available commands.
34
35 * ld, list compatible devices
39 `elektroid-cli` brings the same funcionality than `elektroid` to the command line.
40
41 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.
42
43 These are the available filesystems:
44
45 * `sample`
46 * `raw`
47 * `preset`
48 * `data`
49 * `project`
50 * `sound`
51
52 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.
53
54 These are the available commands:
55
56 * `ls` or `list`
57 * `mkdir`
58 * `rmdir` or `rm` (both behave as `rm -rf`)
59 * `mv`
60 * `cp`
61 * `cl`, clear item
62 * `sw`, swap items
63 * `ul` or `upload`
64 * `dl` or `download`
65
66 Keep in mind that not every filesystem implements all the commands. For instance, samples can not be swapped.
67
68 Provided paths must always be prepended with the device id and a colon (':') e.g., `0:/incoming`.
69
70 ### Device commands
71
72 * `ld` or `ls-devices`, list compatible devices
3673
3774 ```
3875 $ elektroid-cli ld
3976 0 Elektron Digitakt MIDI 1
4077 ```
4178
42 * info, show device info
79 * `info` or `info-device`, show device info including device filesystems
4380
4481 ```
4582 $ elektroid-cli info 0
46 Digitakt 1.11
47 ```
48
49 * df, show size and use of +Drive and RAM
83 Digitakt 1.30 (Digitakt) filesystems=sample,data,project,sound
84 ```
85
86 * `df` or `info-storage`, show size and use of +Drive and RAM
5087
5188 ```
5289 $ elektroid-cli df 0
53 Filesystem Size Used Available Use%
54 +Drive 1006108672 215891968 790216704 21.46%
55 RAM 67108944 15037872 52071072 22.41%
56 ```
57
58 * ls
59
60 It only works for directories. Notice that the first column is the file type, the second is the size in MiB (it is the same unit used in the devices although it is showed there as MB), the third is an internal cksum and the fourth is the sample name.
61
62 ```
63 $ elektroid-cli ls 0:/
64 D 0.00 00000000 incoming
65 F 0.09 3d71644d square
66 ```
67
68 * mkdir
69
70 ```
71 $ elektroid-cli mkdir 0:/samples
72 ```
73
74 * rmdir
75
76 ```
77 $ elektroid-cli rmdir 0:/samples
78 ```
79
80 * upload
81
82 ```
83 $ elektroid-cli upload square.wav 0:/
84 ```
85
86 * download
87
88 ```
89 $ elektroid-cli download 0:/square
90 ```
91
92 * mv
93
94 ```
95 $ elektroid-cli mv 0:/square 0:/sample
96 ```
97
98 * rm
99
100 ```
101 $ elektroid-cli rm 0:/sample
102 ```
90 Storage Size Used Available Use%
91 +Drive 959.50MiB 198.20MiB 761.30MiB 20.66%
92 RAM 64.00MiB 13.43MiB 50.57MiB 20.98%
93 ```
94
95 * `upgrade`, upgrade firmware
96
97 ```
98 $ elektroid-cli upgrade Digitakt_OS1.30.syx 0
99 ```
100
101 ### Sample, raw and preset commands
102
103 * `ls-sample`
104
105 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.
106
107 ```
108 $ elektroid-cli ls-sample 0:/
109 D 0B 00000000 drum machines
110 F 630.34KiB f8711cd9 saw
111 F 1.29MiB 0bbc22bd square
112 ```
113
114 * `mkdir-sample`
115
116 ```
117 $ elektroid-cli mkdir-sample 0:/samples
118 ```
119
120 * `rmdir-sample`
121
122 ```
123 $ elektroid-cli rmdir-sample 0:/samples
124 ```
125
126 * `ul-sample`
127
128 ```
129 $ elektroid-cli ul-sample square.wav 0:/
130 ```
131
132 * `dl-sample`
133
134 ```
135 $ elektroid-cli dl-sample 0:/square
136 ```
137
138 * `mv-sample`
139
140 ```
141 $ elektroid-cli mv-sample 0:/square 0:/sample
142 ```
143
144 * `rm-sample`
145
146 ```
147 $ elektroid-cli rm-sample 0:/sample
148 ```
149
150 ### Data, sound and project commands
151
152 There are a few things to clarify first.
153
154 * All data commands are valid for both projects and sounds although the examples use just sounds.
155
156 * All data commands that use paths to items and not directories use the item index instead the item name.
157
158 Here are the commands.
159
160 * `ls-data`
161
162 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.
163
164 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.
165
166 ```
167 $ elektroid-cli ls-data 0:/
168 D -1 0000 0 0 0B projects
169 D -1 0000 0 0 0B soundbanks
170 ```
171
172 ```
173 $ elektroid-cli ls-data 0:/soundbanks/D
174 F 1 0012 1 1 160B KICK
175 F 2 0012 1 1 160B SNARE
176 ```
177
178 * `cp-data`
179
180 ```
181 $ elektroid-cli cp-data 0:/soundbanks/D/1 0:/soundbanks/D/3
182 $ elektroid-cli ls-data 0:/soundbanks/D
183 F 1 0012 1 1 160B KICK
184 F 2 0012 1 1 160B SNARE
185 F 3 0012 1 1 160B KICK
186 ```
187
188 * `sw-data`
189
190 ```
191 $ elektroid-cli sw-data 0:/soundbanks/D/2 0:/soundbanks/D/3
192 $ elektroid-cli ls-data 0:/soundbanks/D
193 F 1 0012 1 1 160B KICK
194 F 2 0012 1 1 160B KICK
195 F 3 0012 1 1 160B SNARE
196 ```
197
198 * `mv-data`
199
200 ```
201 $ elektroid-cli mv-data 0:/soundbanks/D/3 0:/soundbanks/D/1
202 $ elektroid-cli ls-data 0:/soundbanks/D
203 F 1 0012 1 1 160B SNARE
204 F 2 0012 1 1 160B KICK
205 ```
206
207 * `cl-data`
208
209 ```
210 $ elektroid-cli cl-data 0:/soundbanks/D/1
211 $ elektroid-cli ls-data 0:/soundbanks/D
212 F 2 0012 1 1 160B KICK
213 ```
214
215 * `dl-data`
216
217 ```
218 $ elektroid-cli dl-data 0:/soundbanks/D/1
219 ```
220
221 * `ul-data`
222
223 ```
224 $ elektroid-cli ul-data sound 0:/soundbanks/D
225 ```
11 # Process this file with autoconf to produce a configure script.
22
33 AC_PREREQ([2.69])
4 AC_INIT([elektroid],[1.4],[dagargo@gmail.com])
4 AC_INIT([elektroid],[2.0],[dagargo@gmail.com])
55 AC_CONFIG_SRCDIR([src])
66 AC_CONFIG_HEADERS([config.h])
77 AM_PROG_LIBTOOL
1212 # Checks for programs.
1313 AC_PROG_CC
1414
15 # Define conditional prior to package checks
16 AM_CONDITIONAL([CLI_ONLY], [test "${CLI_ONLY}" == yes])
17 AM_CONDITIONAL([GUI], [test "${CLI_ONLY}" != yes])
18
1519 # Checks for libraries.
16 PKG_CHECK_MODULES(ALSA, alsa >= 1.1.8)
17 PKG_CHECK_MODULES([GTK], [gtk+-3.0])
20 PKG_CHECK_MODULES(ALSA, alsa >= 1.1.3)
21 PKG_CHECK_MODULES(zlib, zlib >= 1.1.8)
22 PKG_CHECK_MODULES(libzip, libzip >= 1.1.2)
23 AM_COND_IF(GUI, [PKG_CHECK_MODULES([GTK], [gtk+-3.0])])
1824
1925 PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.2, ac_cv_sndfile=1, ac_cv_sndfile=0)
2026 AC_DEFINE_UNQUOTED([HAVE_SNDFILE],${ac_cv_sndfile}, [Set to 1 if you have libsndfile.])
2127 AC_SUBST(SNDFILE_CFLAGS)
2228 AC_SUBST(SNDFILE_LIBS)
2329
24 PKG_CHECK_MODULES(SAMPLERATE, samplerate >= 0.1.9, ac_cv_samplerate=1, ac_cv_samplerate=0)
30 PKG_CHECK_MODULES(SAMPLERATE, samplerate >= 0.1.8, ac_cv_samplerate=1, ac_cv_samplerate=0)
2531 AC_DEFINE_UNQUOTED([HAVE_SAMPLERATE],${ac_cv_samplerate}, [Set to 1 if you have libsamplerate.])
2632 AC_SUBST(SAMPLERATE_CFLAGS)
2733 AC_SUBST(SAMPLERATE_LIBS)
2834
29 PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 5.0])
35 AM_COND_IF(GUI, [PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 5.0])])
3036 AC_SUBST(PULSEAUDIO_CFLAGS)
3137 AC_SUBST(PULSEAUDIO_LIBS)
3238
39 AM_COND_IF(GUI, [
3340 AM_GNU_GETTEXT([external])
34 AM_GNU_GETTEXT_VERSION([0.19.8])
41 AM_GNU_GETTEXT_VERSION([0.12.1])
42 ])
3543
3644 # Checks for header files.
37 AC_CHECK_HEADERS([unistd.h limits.h zlib.h])
45 AC_CHECK_HEADERS([unistd.h limits.h])
3846
3947 # Checks for typedefs, structures, and compiler characteristics.
4048
0 if CLI_ONLY
1 dist_man1_MANS = elektroid-cli.1
2 else
03 dist_man1_MANS = elektroid.1 elektroid-cli.1
4 endif
0 .TH ELEKTROID-CLI "1" "Feb 2020"
0 .TH ELEKTROID-CLI "1" "Dec 2021"
1
12 .SH NAME
2 elektroid-cli \- sample transfer CLI application for Elektron devices
3 elektroid-cli \- transfer CLI application for Elektron devices
4
35 .SH SYNOPSIS
46 .B elektroid-cli
57 .RI [ options ]
68 .RI command
9
710 .SH DESCRIPTION
811 .B elektroid-cli
912 provides the same funcionality than elektroid. See man elektroid for the GUI application.
1013 .PP
11 Provided paths must always be prepended with the device id and a colon (':'), e.g. 0:/samples.
12 .SH COMMANDS
14 Provided paths must always be prepended with the device id and a colon (':'), e.g. 0:/samples. Paths pointing to a data, sound or project file use the index of a file instead of its name.
15
16 .SH DEVICE COMMANDS
1317 .TP
14 .B ld
18 [ \fBld\fR | \fBlist-devices\fR ]
1519 List compatible devices
1620 .TP
17 .B info [device number]
21 [ \fBdf\fR | \fBinfo-storage\fR ] device_number
22 Show size and use of +Drive and RAM where available
23 .TP
24 \fBinfo\fR device_number
1825 Show device info
1926 .TP
20 .B ls [device number]:[path to directory]
27 \fBupgrade\fR firmware device_number
28 Upgrade the device
29
30 .SH FILESYSTEM COMMANDS
31 .PP
32 Filesystem commands must be followed by a hyphen ('-') and a filesystem name. The available filesystemas are sample, sound, project, data, preset and raw. Data is an unpackaged form of sound and project and so is raw with regards to preset.
33 .TP
34 [ \fBls\fR | \fBlist\fR ] device_number:path_to_directory
2135 List directory contents
2236 .TP
23 .B mkdir [device number]:[path to directory]
24 Create a directory
37 \fBmkdir\fR device_number:path_to_directory
38 Create a directory and its parent directories as needed
2539 .TP
26 .B rmdir [device number]:[path to directory]
27 Delete a directory. The directory must be empty.
40 [ \fBrmdir\fR | \fBrm\fR ] device_number:path_to_directory
41 Delete a directory recursively
2842 .TP
29 .B upload [sample] [device number]:[path to directory or sample]
30 Upload a sample. If the path does not exist it will be created. The supported audio file formats are aiff, flac, ogg and wav.
43 [ \fBul\fR | \fBupload\fR ] file device_number:path_to_file_or_directory
44 Upload a file. If the path does not exist it will be created. For the sample filesystem, the supported audio file formats are aiff, flac, ogg and wav.
3145 .TP
32 .B download [device number]:[path to sample]
33 Download a sample. Samples will be stored locally as 16-bit, 48kHz wav files.
46 [ \fBdl\fR | \fBdownload\fR ] device_number:path_to_file_or_directory
47 Download a file into the current directory. For the sample filesystem, samples will be stored locally as 16-bit, 48kHz wav files.
3448 .TP
35 .B mv [device number]:[path to origin sample] [device number]:[path to destination directory or sample]
36 Move a sample. If the destination path does not exist it will be created.
49 \fBmv\fR device_number:path_to_file_or_directory device_number:path_to_file_or_directory
50 Move a file. If the destination path does not exist, it will be created.
3751 .TP
38 .B rm [device number]:[path to sample]
39 Delete a sample
52 \fBrm\fR device_number:path_to_file
53 Delete a file
54 .TP
55 \fBcl\fR device_number:path_to_file
56 Clear file
57 .TP
58 \fBcp\fR device_number:path_to_file device_number:path_to_file
59 Copy a file
60 .TP
61 \fBsw\fR device_number:path_to_file device_number:path_to_file
62 Swap files
63
4064 .SH OPTIONS
4165 .TP
4266 \fB\-v\fR
4367 Show verbose output. Use it more than once for more verbosity.
4468 .PP
69
70 .SH EXAMPLES
71 .PP
72 Upload a sample.
73 .TP
74 \tul-sample square.wav 0:/waveforms
75 .PP
76 Download a preset into the current directory.
77 .TP
78 \tdl-raw 0:/snare/snare.mc-snd
79 .PP
80 List projects.
81 .TP
82 \tls-project 0:/
83
4584 .SH "SEE ALSO"
4685 The GitHub page provides some examples: <https://github.com/dagargo/elektroid>
86
4787 .SH "AUTHOR"
4888 elektroid-cli was written by David García Goñi <dagargo@gmail.com>.
4989 .PP
0 .TH ELEKTROID "1" "Feb 2020"
0 .TH ELEKTROID "1" "Dec 2021"
1
12 .SH NAME
2 elektroid \- sample transfer application for Elektron devices
3 elektroid \- transfer application for Elektron devices
4
35 .SH SYNOPSIS
46 .B elektroid
57 .RI [ options ]
8
69 .SH DESCRIPTION
710 .B Elektroid
8 is a GNU/Linux sample transfer application for Elektron devices. See man elektroid-cli for the CLI application.
11 is a GNU/Linux transfer application for Elektron devices. See man elektroid-cli for the CLI application.
912 .PP
10 With Elektroid you can easily upload aiff, flac, ogg and wav audio files into your Elektron sampler. Besides, you can download audio samples from your device to your computer. It can also be used to send and receive MIDI SysEx files.
13 With Elektroid you can easily upload and download audio files, projects, sounds and presets to and from your Elektron device. It can also be used to send and receive MIDI SysEx files.
1114 .PP
12 Elektroid has been reported to work with Model:Samples, Digitakt and Analog Rytm mk1 and mk2.
15 Elektroid has been reported to work with Model:Samples, Model:Cycles, Digitakt, Digitone and Analog Rytm MKI and MKII.
16
1317 .SH OPTIONS
1418 .TP
15 \fB\-l\fR <local directory>
19 \fB\-l\fR, \fB--local-directory\fR <local directory>
1620 Open the provided local directory
1721 .TP
18 \fB\-v\fR
22 \fB\-v\fR, \fB--verbose\fR
1923 Show verbose output. Use it more than once for more verbosity.
24 .TP
25 \fB\-h\fR, \fB--help\fR
26 Show a little help about the options
2027 .PP
28
2129 .SH "AUTHOR"
2230 elektroid was written by David García Goñi <dagargo@gmail.com>.
31
2332 .PP
2433 This manual page was written by Dennis Braun <d_braun@kabelmail.de>
2534 for the Debian project (but may be used by others).
22 en
33 es
44 fr
5 pt_BR
66 msgstr ""
77 "Project-Id-Version: elektroid 1.4\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2021-06-20 17:23+0200\n"
9 "POT-Creation-Date: 2021-12-01 18:58+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:275
19 #: src/elektroid.c:249
20 msgid "Samples"
21 msgstr "Mostres"
22
23 #: src/elektroid.c:251
24 msgid "Presets"
25 msgstr "Programes"
26
27 #: src/elektroid.c:253
28 msgid "Projects"
29 msgstr "Projectes"
30
31 #: src/elektroid.c:255
32 msgid "Sounds"
33 msgstr "Sos"
34
35 #: src/elektroid.c:257 src/elektroid.c:1650 src/elektroid.c:1664
36 msgid "Undefined"
37 msgstr "Indefinit"
38
39 #: src/elektroid.c:398
2040 #, c-format
2141 msgid "Connected to %s%s"
2242 msgstr "Connectat a %s%s"
2343
24 #: src/elektroid.c:283 src/elektroid.c:3172
44 #: src/elektroid.c:406 src/elektroid.c:3215
2545 msgid "Not connected"
2646 msgstr "No connectat"
2747
28 #: src/elektroid.c:424
48 #: src/elektroid.c:549
2949 msgid "Waiting..."
3050 msgstr "Esperant..."
3151
32 #: src/elektroid.c:427
52 #: src/elektroid.c:552
3353 msgid "Sending..."
3454 msgstr "Enviant..."
3555
36 #: src/elektroid.c:431
56 #: src/elektroid.c:556
3757 msgid "Receiving..."
3858 msgstr "Rebent..."
3959
40 #: src/elektroid.c:499
60 #: src/elektroid.c:624
4161 msgid "Receive SysEx"
4262 msgstr "Rep SysEx"
4363
44 #: src/elektroid.c:521
64 #: src/elektroid.c:648
4565 msgid "Save SysEx"
4666 msgstr "Alça SysEx"
4767
48 #: src/elektroid.c:524 src/elektroid.c:629 src/elektroid.c:812
68 #: src/elektroid.c:651 src/elektroid.c:747 src/elektroid.c:915
4969 msgid "_Cancel"
5070 msgstr "_Cancel·la"
5171
52 #: src/elektroid.c:526
72 #: src/elektroid.c:653
5373 msgid "_Save"
5474 msgstr "_Alça"
5575
56 #: src/elektroid.c:530
76 #: src/elektroid.c:657
5777 msgid "Received SysEx"
5878 msgstr "SysEx rebut"
5979
60 #: src/elektroid.c:535 src/elektroid.c:635
80 #: src/elektroid.c:662 src/elektroid.c:753
6181 msgid "SysEx Files"
6282 msgstr "Fitxers SysEx"
6383
64 #: src/elektroid.c:626
84 #: src/elektroid.c:696
85 #, c-format
86 msgid "Error while saving “%s”: %s."
87 msgstr "Error al guardar «%s»: %s."
88
89 #: src/elektroid.c:744
6590 msgid "Open SysEx"
6691 msgstr "Obri SysEx"
6792
68 #: src/elektroid.c:631
93 #: src/elektroid.c:749
6994 msgid "_Open"
7095 msgstr "_Obri"
7196
72 #: src/elektroid.c:659
97 #: src/elektroid.c:770
98 #, c-format
99 msgid "Error while loading “%s”: %s."
100 msgstr "Error al carregar «%s»: %s."
101
102 #: src/elektroid.c:780
73103 msgid "Send SysEx"
74104 msgstr "Envia SysEx"
75105
76 #: src/elektroid.c:779
106 #: src/elektroid.c:882
77107 #, c-format
78108 msgid "Error while deleting “%s”: %s."
79109 msgstr "Error al eliminar «%s»: %s."
80110
81 #: src/elektroid.c:811
111 #: src/elektroid.c:914
82112 msgid "Are you sure you want to delete the selected items?"
83113 msgstr "Està segur de que vol eliminar els elements seleccionats?"
84114
85 #: src/elektroid.c:813
115 #: src/elektroid.c:916
86116 msgid "_Delete"
87117 msgstr "_Elimina"
88118
89 #: src/elektroid.c:867 res/gui.glade:106 res/gui.glade:155
119 #: src/elektroid.c:969 res/gui.glade:130 res/gui.glade:193
90120 msgid "Rename"
91121 msgstr "Canvia el nom"
92122
93 #: src/elektroid.c:885
123 #: src/elektroid.c:987
94124 #, c-format
95125 msgid "Error while renaming to “%s”: %s."
96126 msgstr "Error al canviar el nom a «%s»: %s."
97127
98 #: src/elektroid.c:1617 res/gui.glade:445 res/gui.glade:628
128 #: src/elektroid.c:1550 res/gui.glade:121 res/gui.glade:183 res/gui.glade:184
99129 msgid "Add Directory"
100130 msgstr "Afig directori"
101131
102 #: src/elektroid.c:1635
132 #: src/elektroid.c:1568
103133 #, c-format
104134 msgid "Error while creating dir “%s”: %s."
105135 msgstr "Error al crear el directori «%s»: %s."
106136
107 #: src/elektroid.c:1797
137 #: src/elektroid.c:1640
108138 msgid "Queued"
109139 msgstr "A la cua"
110140
111 #: src/elektroid.c:1799
141 #: src/elektroid.c:1642
112142 msgid "Running"
113143 msgstr "Executant"
114144
115 #: src/elektroid.c:1801
145 #: src/elektroid.c:1644
116146 msgid "Completed"
117147 msgstr "Completada"
118148
119 #: src/elektroid.c:1803
149 #: src/elektroid.c:1646
120150 msgid "Completed with errors"
121151 msgstr "Completada amb errors"
122152
123 #: src/elektroid.c:1805
153 #: src/elektroid.c:1648
124154 msgid "Canceled"
125155 msgstr "Cancel·lada"
126156
127 #: src/elektroid.c:1807 src/elektroid.c:1821
128 msgid "Undefined"
129 msgstr "Indefinit"
130
131 #: src/elektroid.c:1817
157 #: src/elektroid.c:1660
132158 msgid "Upload"
133159 msgstr "Càrrega"
134160
135 #: src/elektroid.c:1819
161 #: src/elektroid.c:1662
136162 msgid "Download"
137163 msgstr "Descàrrega"
138164
139 #: src/elektroid.c:2613 src/elektroid.c:2643
165 #: src/elektroid.c:2518 src/elektroid.c:2559
140166 #, c-format
141167 msgid "Error while moving from “%s” to “%s”: %s."
142168 msgstr "Error al moure de «%s» a «%s»: %s."
143169
144 #: res/gui.glade:55
170 #: res/gui.glade:70
145171 msgid "Upload Selection"
146172 msgstr "Carrega la selecció"
147173
148 #: res/gui.glade:70
174 #: res/gui.glade:85
149175 msgid "Play"
150176 msgstr "Reproduïx"
151177
152 #: res/gui.glade:84
178 #: res/gui.glade:99
153179 msgid "Open With External Editor"
154180 msgstr "Obri amb l'editor extern"
155181
156 #: res/gui.glade:92
182 #: res/gui.glade:107
157183 msgid "Show in File Manager"
158184 msgstr "Mostra al navegador de fitxers"
159185
160 #: res/gui.glade:115 res/gui.glade:164
186 #: res/gui.glade:139 res/gui.glade:202
161187 msgid "Delete"
162188 msgstr "Elimina"
163189
164 #: res/gui.glade:140
190 #: res/gui.glade:168
165191 msgid "Download Selection"
166192 msgstr "Descarrega la selecció"
167193
168 #: res/gui.glade:196
169 msgid "GNU/Linux sample transfer application for Elektron devices"
170 msgstr ""
171 "Aplicació GNU/Linux de transferència de mostres per a dispositius Elektron"
172
173 #: res/gui.glade:199
194 #: res/gui.glade:238
195 msgid "GNU/Linux transfer application for Elektron devices"
196 msgstr "Aplicació GNU/Linux de transferència per a dispositius Elektron"
197
198 #: res/gui.glade:241
174199 msgid "translator-credits"
175200 msgstr "David García Goñi <dagargo@gmail.com>"
176201
177 #: res/gui.glade:250
202 #: res/gui.glade:289
178203 msgid "_Receive SysEx"
179204 msgstr "_Rep SysEx"
180205
181 #: res/gui.glade:263
206 #: res/gui.glade:302
182207 msgid "_Send SysEx"
183208 msgstr "_Envia SysEx"
184209
185 #: res/gui.glade:287
210 #: res/gui.glade:326
186211 msgid "OS _Upgrade"
187212 msgstr "_Actualitza el SO"
188213
189 #: res/gui.glade:311
214 #: res/gui.glade:350
190215 msgid "_About"
191216 msgstr "_Quant a"
192217
193 #: res/gui.glade:424 res/gui.glade:607
218 #: res/gui.glade:434 res/gui.glade:583
194219 msgid "Go to Parent Directory"
195220 msgstr "Ves al directori pare"
196221
197 #: res/gui.glade:466 res/gui.glade:649
222 #: res/gui.glade:455 res/gui.glade:604
198223 msgid "Refresh Directory"
199224 msgstr "Actualitza el directori"
200225
201 #: res/gui.glade:530 res/gui.glade:713 res/gui.glade:1336
226 #: res/gui.glade:512 res/gui.glade:671 res/gui.glade:1362
202227 msgid "Name"
203228 msgstr "Nom"
204229
205 #: res/gui.glade:544 res/gui.glade:727
230 #: res/gui.glade:526 res/gui.glade:685
206231 msgid "Size"
207232 msgstr "Mida"
208233
209 #: res/gui.glade:780
234 #: res/gui.glade:738
210235 msgid "Refresh Devices"
211236 msgstr "Actualitza els dispositius"
212237
213238 #. It is recommended to split the text in two lines if it is too long
214 #: res/gui.glade:860
239 #: res/gui.glade:856
215240 msgid "Auto play"
216241 msgstr ""
217242 "Reproducció\n"
218243 "automàtica"
219244
220 #: res/gui.glade:1092
245 #: res/gui.glade:1088
221246 msgid "Status"
222247 msgstr "Estat"
223248
224 #: res/gui.glade:1103
249 #: res/gui.glade:1099
225250 msgid "Type"
226251 msgstr "Tipus"
227252
228 #: res/gui.glade:1114
253 #: res/gui.glade:1120
229254 msgid "Source"
230255 msgstr "Origen"
231256
232 #: res/gui.glade:1128
257 #: res/gui.glade:1134
233258 msgid "Destination"
234259 msgstr "Destinació"
235260
236 #: res/gui.glade:1143
261 #: res/gui.glade:1149
237262 msgid "Progress"
238263 msgstr "Progrés"
239264
240 #: res/gui.glade:1175
265 #: res/gui.glade:1181
241266 msgid "Cancel Tasks"
242267 msgstr "Cancel·la les tasques"
243268
244 #: res/gui.glade:1196
269 #: res/gui.glade:1202
245270 msgid "Remove Queued Tasks"
246271 msgstr "Elimina les tasques de la cua"
247272
248 #: res/gui.glade:1217
273 #: res/gui.glade:1223
249274 msgid "Clear Finished Tasks"
250275 msgstr "Neteja les tasques terminadas"
66 msgstr ""
77 "Project-Id-Version: elektroid 1.4\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2021-06-20 17:23+0200\n"
9 "POT-Creation-Date: 2021-12-01 18:58+0100\n"
1010 "PO-Revision-Date: 2021-01-11 22:00+0100\n"
1111 "Last-Translator: Dennis Braun <d_braun@kabelmail.de>\n"
1212 "Language-Team: German\n"
1616 "Content-Transfer-Encoding: 8bit\n"
1717 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
1818
19 #: src/elektroid.c:275
19 #: src/elektroid.c:249
20 msgid "Samples"
21 msgstr "Samples"
22
23 #: src/elektroid.c:251
24 msgid "Presets"
25 msgstr "Presets"
26
27 #: src/elektroid.c:253
28 msgid "Projects"
29 msgstr "Projekte"
30
31 #: src/elektroid.c:255
32 msgid "Sounds"
33 msgstr "Sounds"
34
35 #: src/elektroid.c:257 src/elektroid.c:1650 src/elektroid.c:1664
36 msgid "Undefined"
37 msgstr "Undefiniert"
38
39 #: src/elektroid.c:398
2040 #, c-format
2141 msgid "Connected to %s%s"
2242 msgstr "Verbunden mit %s%s"
2343
24 #: src/elektroid.c:283 src/elektroid.c:3172
44 #: src/elektroid.c:406 src/elektroid.c:3215
2545 msgid "Not connected"
2646 msgstr "Nicht verbunden"
2747
28 #: src/elektroid.c:424
48 #: src/elektroid.c:549
2949 msgid "Waiting..."
3050 msgstr "Warte..."
3151
32 #: src/elektroid.c:427
52 #: src/elektroid.c:552
3353 msgid "Sending..."
3454 msgstr "Sende..."
3555
36 #: src/elektroid.c:431
56 #: src/elektroid.c:556
3757 msgid "Receiving..."
3858 msgstr "Empfange..."
3959
40 #: src/elektroid.c:499
60 #: src/elektroid.c:624
4161 msgid "Receive SysEx"
4262 msgstr "Empfange SysEx"
4363
44 #: src/elektroid.c:521
64 #: src/elektroid.c:648
4565 msgid "Save SysEx"
4666 msgstr "Speichere SysEx"
4767
48 #: src/elektroid.c:524 src/elektroid.c:629 src/elektroid.c:812
68 #: src/elektroid.c:651 src/elektroid.c:747 src/elektroid.c:915
4969 msgid "_Cancel"
5070 msgstr "_Abbrechen"
5171
52 #: src/elektroid.c:526
72 #: src/elektroid.c:653
5373 msgid "_Save"
5474 msgstr "_Speichern"
5575
56 #: src/elektroid.c:530
76 #: src/elektroid.c:657
5777 msgid "Received SysEx"
5878 msgstr "SysEx empfangen"
5979
60 #: src/elektroid.c:535 src/elektroid.c:635
80 #: src/elektroid.c:662 src/elektroid.c:753
6181 msgid "SysEx Files"
6282 msgstr "SysEx Dateien"
6383
64 #: src/elektroid.c:626
84 #: src/elektroid.c:696
85 #, fuzzy, c-format
86 msgid "Error while saving “%s”: %s."
87 msgstr "Fehler beim Löschen »%s«: %s."
88
89 #: src/elektroid.c:744
6590 msgid "Open SysEx"
6691 msgstr "Öffne SysEx"
6792
68 #: src/elektroid.c:631
93 #: src/elektroid.c:749
6994 msgid "_Open"
7095 msgstr "_Öffnen"
7196
72 #: src/elektroid.c:659
97 #: src/elektroid.c:770
98 #, fuzzy, c-format
99 msgid "Error while loading “%s”: %s."
100 msgstr "Fehler beim Löschen »%s«: %s."
101
102 #: src/elektroid.c:780
73103 msgid "Send SysEx"
74104 msgstr "Sende SysEx"
75105
76 #: src/elektroid.c:779
106 #: src/elektroid.c:882
77107 #, c-format
78108 msgid "Error while deleting “%s”: %s."
79109 msgstr "Fehler beim Löschen »%s«: %s."
80110
81 #: src/elektroid.c:811
111 #: src/elektroid.c:914
82112 msgid "Are you sure you want to delete the selected items?"
83113 msgstr "Bist du sicher das du die ausgewählten Elemente löschen möchtest?"
84114
85 #: src/elektroid.c:813
115 #: src/elektroid.c:916
86116 msgid "_Delete"
87117 msgstr "_Löschen"
88118
89 #: src/elektroid.c:867 res/gui.glade:106 res/gui.glade:155
119 #: src/elektroid.c:969 res/gui.glade:130 res/gui.glade:193
90120 msgid "Rename"
91121 msgstr "Umbenennen"
92122
93 #: src/elektroid.c:885
123 #: src/elektroid.c:987
94124 #, c-format
95125 msgid "Error while renaming to “%s”: %s."
96126 msgstr "Fehler beim Umbenennen von »%s«: %s."
97127
98 #: src/elektroid.c:1617 res/gui.glade:445 res/gui.glade:628
128 #: src/elektroid.c:1550 res/gui.glade:121 res/gui.glade:183 res/gui.glade:184
99129 msgid "Add Directory"
100130 msgstr "Verzeichnis hinzufügen"
101131
102 #: src/elektroid.c:1635
132 #: src/elektroid.c:1568
103133 #, c-format
104134 msgid "Error while creating dir “%s”: %s."
105135 msgstr "Fehler beim Erstellen des Verzeichnisses »%s«: %s."
106136
107 #: src/elektroid.c:1797
137 #: src/elektroid.c:1640
108138 msgid "Queued"
109139 msgstr "In der Warteschlange"
110140
111 #: src/elektroid.c:1799
141 #: src/elektroid.c:1642
112142 msgid "Running"
113143 msgstr "Wird ausgeführt"
114144
115 #: src/elektroid.c:1801
145 #: src/elektroid.c:1644
116146 msgid "Completed"
117147 msgstr "Fertig"
118148
119 #: src/elektroid.c:1803
149 #: src/elektroid.c:1646
120150 msgid "Completed with errors"
121151 msgstr "Abgeschlossen mit Fehlern"
122152
123 #: src/elektroid.c:1805
153 #: src/elektroid.c:1648
124154 msgid "Canceled"
125155 msgstr "Abgebrochen"
126156
127 #: src/elektroid.c:1807 src/elektroid.c:1821
128 msgid "Undefined"
129 msgstr "Undefiniert"
130
131 #: src/elektroid.c:1817
157 #: src/elektroid.c:1660
132158 msgid "Upload"
133159 msgstr "Hochladen"
134160
135 #: src/elektroid.c:1819
161 #: src/elektroid.c:1662
136162 msgid "Download"
137163 msgstr "Herunterladen"
138164
139 #: src/elektroid.c:2613 src/elektroid.c:2643
165 #: src/elektroid.c:2518 src/elektroid.c:2559
140166 #, c-format
141167 msgid "Error while moving from “%s” to “%s”: %s."
142168 msgstr "Fehler beim Verschieben von »%s« nach »%s«: %s."
143169
144 #: res/gui.glade:55
170 #: res/gui.glade:70
145171 msgid "Upload Selection"
146172 msgstr "Upload Auswahl"
147173
148 #: res/gui.glade:70
174 #: res/gui.glade:85
149175 msgid "Play"
150176 msgstr "Abspielen"
151177
152 #: res/gui.glade:84
178 #: res/gui.glade:99
153179 msgid "Open With External Editor"
154180 msgstr "Öffnen mit externen Editor"
155181
156 #: res/gui.glade:92
182 #: res/gui.glade:107
157183 msgid "Show in File Manager"
158184 msgstr "Im Dateimanager _Anzeigen"
159185
160 #: res/gui.glade:115 res/gui.glade:164
186 #: res/gui.glade:139 res/gui.glade:202
161187 msgid "Delete"
162188 msgstr "Löschen"
163189
164 #: res/gui.glade:140
190 #: res/gui.glade:168
165191 msgid "Download Selection"
166192 msgstr "Download Auswahl"
167193
168 #: res/gui.glade:196
169 msgid "GNU/Linux sample transfer application for Elektron devices"
170 msgstr "GNU/Linux Sample Transfer Anwendung für Elektron Instrumente"
171
172 #: res/gui.glade:199
194 #: res/gui.glade:238
195 #, fuzzy
196 msgid "GNU/Linux transfer application for Elektron devices"
197 msgstr "GNU/Linux Transfer Anwendung für Elektron Instrumente"
198
199 #: res/gui.glade:241
173200 msgid "translator-credits"
174201 msgstr "Dennis Braun <d_braun@kabelmail.de>"
175202
176 #: res/gui.glade:250
203 #: res/gui.glade:289
177204 msgid "_Receive SysEx"
178205 msgstr "_Empfange SysEx"
179206
180 #: res/gui.glade:263
207 #: res/gui.glade:302
181208 msgid "_Send SysEx"
182209 msgstr "_Sende SysEx"
183210
184 #: res/gui.glade:287
211 #: res/gui.glade:326
185212 msgid "OS _Upgrade"
186213 msgstr "OS _Aktualisierung"
187214
188 #: res/gui.glade:311
215 #: res/gui.glade:350
189216 msgid "_About"
190217 msgstr "_Info"
191218
192 #: res/gui.glade:424 res/gui.glade:607
219 #: res/gui.glade:434 res/gui.glade:583
193220 msgid "Go to Parent Directory"
194221 msgstr "Gehe zum Überverzeichnis"
195222
196 #: res/gui.glade:466 res/gui.glade:649
223 #: res/gui.glade:455 res/gui.glade:604
197224 msgid "Refresh Directory"
198225 msgstr "Aktualisiere Verzeichnis"
199226
200 #: res/gui.glade:530 res/gui.glade:713 res/gui.glade:1336
227 #: res/gui.glade:512 res/gui.glade:671 res/gui.glade:1362
201228 msgid "Name"
202229 msgstr "Name"
203230
204 #: res/gui.glade:544 res/gui.glade:727
231 #: res/gui.glade:526 res/gui.glade:685
205232 msgid "Size"
206233 msgstr "Größe"
207234
208 #: res/gui.glade:780
235 #: res/gui.glade:738
209236 msgid "Refresh Devices"
210237 msgstr "Aktualisiere Geräte"
211238
212239 #. It is recommended to split the text in two lines if it is too long
213 #: res/gui.glade:860
240 #: res/gui.glade:856
214241 msgid "Auto play"
215242 msgstr "Auto Play"
216243
217 #: res/gui.glade:1092
244 #: res/gui.glade:1088
218245 msgid "Status"
219246 msgstr "Status"
220247
221 #: res/gui.glade:1103
248 #: res/gui.glade:1099
222249 msgid "Type"
223250 msgstr "Typ"
224251
225 #: res/gui.glade:1114
252 #: res/gui.glade:1120
226253 msgid "Source"
227254 msgstr "Quelle"
228255
229 #: res/gui.glade:1128
256 #: res/gui.glade:1134
230257 msgid "Destination"
231258 msgstr "Ziel"
232259
233 #: res/gui.glade:1143
260 #: res/gui.glade:1149
234261 msgid "Progress"
235262 msgstr "Fortschritt"
236263
237 #: res/gui.glade:1175
264 #: res/gui.glade:1181
238265 msgid "Cancel Tasks"
239266 msgstr "Aufgaben abbrechen"
240267
241 #: res/gui.glade:1196
268 #: res/gui.glade:1202
242269 msgid "Remove Queued Tasks"
243270 msgstr "Lösche Aufgaben in der Warteschlange"
244271
245 #: res/gui.glade:1217
272 #: res/gui.glade:1223
246273 msgid "Clear Finished Tasks"
247274 msgstr "Abgeschlossene Aufgaben aufräumen"
55 #, fuzzy
66 msgid ""
77 msgstr ""
8 "Project-Id-Version: elektroid 1.4\n"
8 "Project-Id-Version: elektroid 2.0-beta\n"
99 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
10 "POT-Creation-Date: 2021-06-20 17:23+0200\n"
10 "POT-Creation-Date: 2021-12-01 18:58+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:275
19 #: src/elektroid.c:249
20 msgid "Samples"
21 msgstr ""
22
23 #: src/elektroid.c:251
24 msgid "Presets"
25 msgstr ""
26
27 #: src/elektroid.c:253
28 msgid "Projects"
29 msgstr ""
30
31 #: src/elektroid.c:255
32 msgid "Sounds"
33 msgstr ""
34
35 #: src/elektroid.c:257 src/elektroid.c:1650 src/elektroid.c:1664
36 msgid "Undefined"
37 msgstr ""
38
39 #: src/elektroid.c:398
2040 #, c-format
2141 msgid "Connected to %s%s"
2242 msgstr ""
2343
24 #: src/elektroid.c:283 src/elektroid.c:3172
44 #: src/elektroid.c:406 src/elektroid.c:3215
2545 msgid "Not connected"
2646 msgstr ""
2747
28 #: src/elektroid.c:424
48 #: src/elektroid.c:549
2949 msgid "Waiting..."
3050 msgstr ""
3151
32 #: src/elektroid.c:427
52 #: src/elektroid.c:552
3353 msgid "Sending..."
3454 msgstr ""
3555
36 #: src/elektroid.c:431
56 #: src/elektroid.c:556
3757 msgid "Receiving..."
3858 msgstr ""
3959
40 #: src/elektroid.c:499
60 #: src/elektroid.c:624
4161 msgid "Receive SysEx"
4262 msgstr ""
4363
44 #: src/elektroid.c:521
64 #: src/elektroid.c:648
4565 msgid "Save SysEx"
4666 msgstr ""
4767
48 #: src/elektroid.c:524 src/elektroid.c:629 src/elektroid.c:812
68 #: src/elektroid.c:651 src/elektroid.c:747 src/elektroid.c:915
4969 msgid "_Cancel"
5070 msgstr ""
5171
52 #: src/elektroid.c:526
72 #: src/elektroid.c:653
5373 msgid "_Save"
5474 msgstr ""
5575
56 #: src/elektroid.c:530
76 #: src/elektroid.c:657
5777 msgid "Received SysEx"
5878 msgstr ""
5979
60 #: src/elektroid.c:535 src/elektroid.c:635
80 #: src/elektroid.c:662 src/elektroid.c:753
6181 msgid "SysEx Files"
6282 msgstr ""
6383
64 #: src/elektroid.c:626
84 #: src/elektroid.c:696
85 #, c-format
86 msgid "Error while saving “%s”: %s."
87 msgstr ""
88
89 #: src/elektroid.c:744
6590 msgid "Open SysEx"
6691 msgstr ""
6792
68 #: src/elektroid.c:631
93 #: src/elektroid.c:749
6994 msgid "_Open"
7095 msgstr ""
7196
72 #: src/elektroid.c:659
97 #: src/elektroid.c:770
98 #, c-format
99 msgid "Error while loading “%s”: %s."
100 msgstr ""
101
102 #: src/elektroid.c:780
73103 msgid "Send SysEx"
74104 msgstr ""
75105
76 #: src/elektroid.c:779
106 #: src/elektroid.c:882
77107 #, c-format
78108 msgid "Error while deleting “%s”: %s."
79109 msgstr ""
80110
81 #: src/elektroid.c:811
111 #: src/elektroid.c:914
82112 msgid "Are you sure you want to delete the selected items?"
83113 msgstr ""
84114
85 #: src/elektroid.c:813
115 #: src/elektroid.c:916
86116 msgid "_Delete"
87117 msgstr ""
88118
89 #: src/elektroid.c:867 res/gui.glade:106 res/gui.glade:155
119 #: src/elektroid.c:969 res/gui.glade:130 res/gui.glade:193
90120 msgid "Rename"
91121 msgstr ""
92122
93 #: src/elektroid.c:885
123 #: src/elektroid.c:987
94124 #, c-format
95125 msgid "Error while renaming to “%s”: %s."
96126 msgstr ""
97127
98 #: src/elektroid.c:1617 res/gui.glade:445 res/gui.glade:628
128 #: src/elektroid.c:1550 res/gui.glade:121 res/gui.glade:183 res/gui.glade:184
99129 msgid "Add Directory"
100130 msgstr ""
101131
102 #: src/elektroid.c:1635
132 #: src/elektroid.c:1568
103133 #, c-format
104134 msgid "Error while creating dir “%s”: %s."
105135 msgstr ""
106136
107 #: src/elektroid.c:1797
137 #: src/elektroid.c:1640
108138 msgid "Queued"
109139 msgstr ""
110140
111 #: src/elektroid.c:1799
141 #: src/elektroid.c:1642
112142 msgid "Running"
113143 msgstr ""
114144
115 #: src/elektroid.c:1801
145 #: src/elektroid.c:1644
116146 msgid "Completed"
117147 msgstr ""
118148
119 #: src/elektroid.c:1803
149 #: src/elektroid.c:1646
120150 msgid "Completed with errors"
121151 msgstr ""
122152
123 #: src/elektroid.c:1805
153 #: src/elektroid.c:1648
124154 msgid "Canceled"
125155 msgstr ""
126156
127 #: src/elektroid.c:1807 src/elektroid.c:1821
128 msgid "Undefined"
129 msgstr ""
130
131 #: src/elektroid.c:1817
157 #: src/elektroid.c:1660
132158 msgid "Upload"
133159 msgstr ""
134160
135 #: src/elektroid.c:1819
161 #: src/elektroid.c:1662
136162 msgid "Download"
137163 msgstr ""
138164
139 #: src/elektroid.c:2613 src/elektroid.c:2643
165 #: src/elektroid.c:2518 src/elektroid.c:2559
140166 #, c-format
141167 msgid "Error while moving from “%s” to “%s”: %s."
142168 msgstr ""
143169
144 #: res/gui.glade:55
170 #: res/gui.glade:70
145171 msgid "Upload Selection"
146172 msgstr ""
147173
148 #: res/gui.glade:70
174 #: res/gui.glade:85
149175 msgid "Play"
150176 msgstr ""
151177
152 #: res/gui.glade:84
178 #: res/gui.glade:99
153179 msgid "Open With External Editor"
154180 msgstr ""
155181
156 #: res/gui.glade:92
182 #: res/gui.glade:107
157183 msgid "Show in File Manager"
158184 msgstr ""
159185
160 #: res/gui.glade:115 res/gui.glade:164
186 #: res/gui.glade:139 res/gui.glade:202
161187 msgid "Delete"
162188 msgstr ""
163189
164 #: res/gui.glade:140
190 #: res/gui.glade:168
165191 msgid "Download Selection"
166192 msgstr ""
167193
168 #: res/gui.glade:196
169 msgid "GNU/Linux sample transfer application for Elektron devices"
170 msgstr ""
171
172 #: res/gui.glade:199
194 #: res/gui.glade:238
195 msgid "GNU/Linux transfer application for Elektron devices"
196 msgstr ""
197
198 #: res/gui.glade:241
173199 msgid "translator-credits"
174200 msgstr ""
175201
176 #: res/gui.glade:250
202 #: res/gui.glade:289
177203 msgid "_Receive SysEx"
178204 msgstr ""
179205
180 #: res/gui.glade:263
206 #: res/gui.glade:302
181207 msgid "_Send SysEx"
182208 msgstr ""
183209
184 #: res/gui.glade:287
210 #: res/gui.glade:326
185211 msgid "OS _Upgrade"
186212 msgstr ""
187213
188 #: res/gui.glade:311
214 #: res/gui.glade:350
189215 msgid "_About"
190216 msgstr ""
191217
192 #: res/gui.glade:424 res/gui.glade:607
218 #: res/gui.glade:434 res/gui.glade:583
193219 msgid "Go to Parent Directory"
194220 msgstr ""
195221
196 #: res/gui.glade:466 res/gui.glade:649
222 #: res/gui.glade:455 res/gui.glade:604
197223 msgid "Refresh Directory"
198224 msgstr ""
199225
200 #: res/gui.glade:530 res/gui.glade:713 res/gui.glade:1336
226 #: res/gui.glade:512 res/gui.glade:671 res/gui.glade:1362
201227 msgid "Name"
202228 msgstr ""
203229
204 #: res/gui.glade:544 res/gui.glade:727
230 #: res/gui.glade:526 res/gui.glade:685
205231 msgid "Size"
206232 msgstr ""
207233
208 #: res/gui.glade:780
234 #: res/gui.glade:738
209235 msgid "Refresh Devices"
210236 msgstr ""
211237
212238 #. It is recommended to split the text in two lines if it is too long
213 #: res/gui.glade:860
239 #: res/gui.glade:856
214240 msgid "Auto play"
215241 msgstr ""
216242
217 #: res/gui.glade:1092
243 #: res/gui.glade:1088
218244 msgid "Status"
219245 msgstr ""
220246
221 #: res/gui.glade:1103
247 #: res/gui.glade:1099
222248 msgid "Type"
223249 msgstr ""
224250
225 #: res/gui.glade:1114
251 #: res/gui.glade:1120
226252 msgid "Source"
227253 msgstr ""
228254
229 #: res/gui.glade:1128
255 #: res/gui.glade:1134
230256 msgid "Destination"
231257 msgstr ""
232258
233 #: res/gui.glade:1143
259 #: res/gui.glade:1149
234260 msgid "Progress"
235261 msgstr ""
236262
237 #: res/gui.glade:1175
263 #: res/gui.glade:1181
238264 msgid "Cancel Tasks"
239265 msgstr ""
240266
241 #: res/gui.glade:1196
267 #: res/gui.glade:1202
242268 msgid "Remove Queued Tasks"
243269 msgstr ""
244270
245 #: res/gui.glade:1217
271 #: res/gui.glade:1223
246272 msgid "Clear Finished Tasks"
247273 msgstr ""
66 msgstr ""
77 "Project-Id-Version: elektroid 1.4\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2021-06-20 17:23+0200\n"
9 "POT-Creation-Date: 2021-12-01 18:58+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:275
19 #: src/elektroid.c:249
20 msgid "Samples"
21 msgstr "Samples"
22
23 #: src/elektroid.c:251
24 msgid "Presets"
25 msgstr "Presets"
26
27 #: src/elektroid.c:253
28 msgid "Projects"
29 msgstr "Projects"
30
31 #: src/elektroid.c:255
32 msgid "Sounds"
33 msgstr "Sounds"
34
35 #: src/elektroid.c:257 src/elektroid.c:1650 src/elektroid.c:1664
36 msgid "Undefined"
37 msgstr "Undefined"
38
39 #: src/elektroid.c:398
2040 #, c-format
2141 msgid "Connected to %s%s"
2242 msgstr "Connected to %s%s"
2343
24 #: src/elektroid.c:283 src/elektroid.c:3172
44 #: src/elektroid.c:406 src/elektroid.c:3215
2545 msgid "Not connected"
2646 msgstr "Not connected"
2747
28 #: src/elektroid.c:424
48 #: src/elektroid.c:549
2949 msgid "Waiting..."
3050 msgstr "Waiting..."
3151
32 #: src/elektroid.c:427
52 #: src/elektroid.c:552
3353 msgid "Sending..."
3454 msgstr "Sending..."
3555
36 #: src/elektroid.c:431
56 #: src/elektroid.c:556
3757 msgid "Receiving..."
3858 msgstr "Receiving..."
3959
40 #: src/elektroid.c:499
60 #: src/elektroid.c:624
4161 msgid "Receive SysEx"
4262 msgstr "Receive SysEx"
4363
44 #: src/elektroid.c:521
64 #: src/elektroid.c:648
4565 msgid "Save SysEx"
4666 msgstr "Save SysEx"
4767
48 #: src/elektroid.c:524 src/elektroid.c:629 src/elektroid.c:812
68 #: src/elektroid.c:651 src/elektroid.c:747 src/elektroid.c:915
4969 msgid "_Cancel"
5070 msgstr "_Cancel"
5171
52 #: src/elektroid.c:526
72 #: src/elektroid.c:653
5373 msgid "_Save"
5474 msgstr "_Save"
5575
56 #: src/elektroid.c:530
76 #: src/elektroid.c:657
5777 msgid "Received SysEx"
5878 msgstr "Received SysEx"
5979
60 #: src/elektroid.c:535 src/elektroid.c:635
80 #: src/elektroid.c:662 src/elektroid.c:753
6181 msgid "SysEx Files"
6282 msgstr "SysEx Files"
6383
64 #: src/elektroid.c:626
84 #: src/elektroid.c:696
85 #, c-format
86 msgid "Error while saving “%s”: %s."
87 msgstr "Error while saving “%s”: %s."
88
89 #: src/elektroid.c:744
6590 msgid "Open SysEx"
6691 msgstr "Open SysEx"
6792
68 #: src/elektroid.c:631
93 #: src/elektroid.c:749
6994 msgid "_Open"
7095 msgstr "_Open"
7196
72 #: src/elektroid.c:659
97 #: src/elektroid.c:770
98 #, c-format
99 msgid "Error while loading “%s”: %s."
100 msgstr "Error while loading “%s”: %s."
101
102 #: src/elektroid.c:780
73103 msgid "Send SysEx"
74104 msgstr "Send SysEx"
75105
76 #: src/elektroid.c:779
106 #: src/elektroid.c:882
77107 #, c-format
78108 msgid "Error while deleting “%s”: %s."
79109 msgstr "Error while deleting “%s”: %s."
80110
81 #: src/elektroid.c:811
111 #: src/elektroid.c:914
82112 msgid "Are you sure you want to delete the selected items?"
83113 msgstr "Are you sure you want to delete the selected items?"
84114
85 #: src/elektroid.c:813
115 #: src/elektroid.c:916
86116 msgid "_Delete"
87117 msgstr "_Delete"
88118
89 #: src/elektroid.c:867 res/gui.glade:106 res/gui.glade:155
119 #: src/elektroid.c:969 res/gui.glade:130 res/gui.glade:193
90120 msgid "Rename"
91121 msgstr "Rename"
92122
93 #: src/elektroid.c:885
123 #: src/elektroid.c:987
94124 #, c-format
95125 msgid "Error while renaming to “%s”: %s."
96126 msgstr "Error while renaming to “%s”: %s."
97127
98 #: src/elektroid.c:1617 res/gui.glade:445 res/gui.glade:628
128 #: src/elektroid.c:1550 res/gui.glade:121 res/gui.glade:183 res/gui.glade:184
99129 msgid "Add Directory"
100130 msgstr "Add Directory"
101131
102 #: src/elektroid.c:1635
132 #: src/elektroid.c:1568
103133 #, c-format
104134 msgid "Error while creating dir “%s”: %s."
105135 msgstr "Error while creating dir “%s”: %s."
106136
107 #: src/elektroid.c:1797
137 #: src/elektroid.c:1640
108138 msgid "Queued"
109139 msgstr "Queued"
110140
111 #: src/elektroid.c:1799
141 #: src/elektroid.c:1642
112142 msgid "Running"
113143 msgstr "Running"
114144
115 #: src/elektroid.c:1801
145 #: src/elektroid.c:1644
116146 msgid "Completed"
117147 msgstr "Completed"
118148
119 #: src/elektroid.c:1803
149 #: src/elektroid.c:1646
120150 msgid "Completed with errors"
121151 msgstr "Completed with errors"
122152
123 #: src/elektroid.c:1805
153 #: src/elektroid.c:1648
124154 msgid "Canceled"
125155 msgstr "Canceled"
126156
127 #: src/elektroid.c:1807 src/elektroid.c:1821
128 msgid "Undefined"
129 msgstr "Undefined"
130
131 #: src/elektroid.c:1817
157 #: src/elektroid.c:1660
132158 msgid "Upload"
133159 msgstr "Upload"
134160
135 #: src/elektroid.c:1819
161 #: src/elektroid.c:1662
136162 msgid "Download"
137163 msgstr "Download"
138164
139 #: src/elektroid.c:2613 src/elektroid.c:2643
165 #: src/elektroid.c:2518 src/elektroid.c:2559
140166 #, c-format
141167 msgid "Error while moving from “%s” to “%s”: %s."
142168 msgstr "Error while moving from “%s” to “%s”: %s."
143169
144 #: res/gui.glade:55
170 #: res/gui.glade:70
145171 msgid "Upload Selection"
146172 msgstr "Upload Selection"
147173
148 #: res/gui.glade:70
174 #: res/gui.glade:85
149175 msgid "Play"
150176 msgstr "Play"
151177
152 #: res/gui.glade:84
178 #: res/gui.glade:99
153179 msgid "Open With External Editor"
154180 msgstr "Open With External Editor"
155181
156 #: res/gui.glade:92
182 #: res/gui.glade:107
157183 msgid "Show in File Manager"
158184 msgstr "Show in File Manager"
159185
160 #: res/gui.glade:115 res/gui.glade:164
186 #: res/gui.glade:139 res/gui.glade:202
161187 msgid "Delete"
162188 msgstr "Delete"
163189
164 #: res/gui.glade:140
190 #: res/gui.glade:168
165191 msgid "Download Selection"
166192 msgstr "Download selection"
167193
168 #: res/gui.glade:196
169 msgid "GNU/Linux sample transfer application for Elektron devices"
170 msgstr "GNU/Linux sample transfer application for Elektron devices"
171
172 #: res/gui.glade:199
194 #: res/gui.glade:238
195 msgid "GNU/Linux transfer application for Elektron devices"
196 msgstr "GNU/Linux transfer application for Elektron devices"
197
198 #: res/gui.glade:241
173199 msgid "translator-credits"
174200 msgstr "David García Goñi <dagargo@gmail.com>"
175201
176 #: res/gui.glade:250
202 #: res/gui.glade:289
177203 msgid "_Receive SysEx"
178204 msgstr "_Receive SysEx"
179205
180 #: res/gui.glade:263
206 #: res/gui.glade:302
181207 msgid "_Send SysEx"
182208 msgstr "_Send SysEx"
183209
184 #: res/gui.glade:287
210 #: res/gui.glade:326
185211 msgid "OS _Upgrade"
186212 msgstr "OS _Upgrade"
187213
188 #: res/gui.glade:311
214 #: res/gui.glade:350
189215 msgid "_About"
190216 msgstr "_About"
191217
192 #: res/gui.glade:424 res/gui.glade:607
218 #: res/gui.glade:434 res/gui.glade:583
193219 msgid "Go to Parent Directory"
194220 msgstr "Go to Parent Directory"
195221
196 #: res/gui.glade:466 res/gui.glade:649
222 #: res/gui.glade:455 res/gui.glade:604
197223 msgid "Refresh Directory"
198224 msgstr "Refresh Directory"
199225
200 #: res/gui.glade:530 res/gui.glade:713 res/gui.glade:1336
226 #: res/gui.glade:512 res/gui.glade:671 res/gui.glade:1362
201227 msgid "Name"
202228 msgstr "Name"
203229
204 #: res/gui.glade:544 res/gui.glade:727
230 #: res/gui.glade:526 res/gui.glade:685
205231 msgid "Size"
206232 msgstr "Size"
207233
208 #: res/gui.glade:780
234 #: res/gui.glade:738
209235 msgid "Refresh Devices"
210236 msgstr "Refresh Devices"
211237
212238 #. It is recommended to split the text in two lines if it is too long
213 #: res/gui.glade:860
239 #: res/gui.glade:856
214240 msgid "Auto play"
215241 msgstr "Auto play"
216242
217 #: res/gui.glade:1092
243 #: res/gui.glade:1088
218244 msgid "Status"
219245 msgstr "Status"
220246
221 #: res/gui.glade:1103
247 #: res/gui.glade:1099
222248 msgid "Type"
223249 msgstr "Type"
224250
225 #: res/gui.glade:1114
251 #: res/gui.glade:1120
226252 msgid "Source"
227253 msgstr "Source"
228254
229 #: res/gui.glade:1128
255 #: res/gui.glade:1134
230256 msgid "Destination"
231257 msgstr "Destination"
232258
233 #: res/gui.glade:1143
259 #: res/gui.glade:1149
234260 msgid "Progress"
235261 msgstr "Progress"
236262
237 #: res/gui.glade:1175
263 #: res/gui.glade:1181
238264 msgid "Cancel Tasks"
239265 msgstr "Cancel Tasks"
240266
241 #: res/gui.glade:1196
267 #: res/gui.glade:1202
242268 msgid "Remove Queued Tasks"
243269 msgstr "Remove Queued Tasks"
244270
245 #: res/gui.glade:1217
271 #: res/gui.glade:1223
246272 msgid "Clear Finished Tasks"
247273 msgstr "Clear Finished Tasks"
66 msgstr ""
77 "Project-Id-Version: elektroid 1.4\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2021-06-20 17:23+0200\n"
9 "POT-Creation-Date: 2021-12-01 18:58+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:275
19 #: src/elektroid.c:249
20 msgid "Samples"
21 msgstr "Muestras"
22
23 #: src/elektroid.c:251
24 msgid "Presets"
25 msgstr "Programas"
26
27 #: src/elektroid.c:253
28 msgid "Projects"
29 msgstr "Proyectos"
30
31 #: src/elektroid.c:255
32 msgid "Sounds"
33 msgstr "Sonidos"
34
35 #: src/elektroid.c:257 src/elektroid.c:1650 src/elektroid.c:1664
36 msgid "Undefined"
37 msgstr "Indefinido"
38
39 #: src/elektroid.c:398
2040 #, c-format
2141 msgid "Connected to %s%s"
2242 msgstr "Conectado a %s%s"
2343
24 #: src/elektroid.c:283 src/elektroid.c:3172
44 #: src/elektroid.c:406 src/elektroid.c:3215
2545 msgid "Not connected"
2646 msgstr "No conectado"
2747
28 #: src/elektroid.c:424
48 #: src/elektroid.c:549
2949 msgid "Waiting..."
3050 msgstr "Esperando..."
3151
32 #: src/elektroid.c:427
52 #: src/elektroid.c:552
3353 msgid "Sending..."
3454 msgstr "Enviando..."
3555
36 #: src/elektroid.c:431
56 #: src/elektroid.c:556
3757 msgid "Receiving..."
3858 msgstr "Recibiendo..."
3959
40 #: src/elektroid.c:499
60 #: src/elektroid.c:624
4161 msgid "Receive SysEx"
4262 msgstr "Recibir SysEx"
4363
44 #: src/elektroid.c:521
64 #: src/elektroid.c:648
4565 msgid "Save SysEx"
4666 msgstr "Guardar SysEx"
4767
48 #: src/elektroid.c:524 src/elektroid.c:629 src/elektroid.c:812
68 #: src/elektroid.c:651 src/elektroid.c:747 src/elektroid.c:915
4969 msgid "_Cancel"
5070 msgstr "_Cancelar"
5171
52 #: src/elektroid.c:526
72 #: src/elektroid.c:653
5373 msgid "_Save"
5474 msgstr "_Guardar"
5575
56 #: src/elektroid.c:530
76 #: src/elektroid.c:657
5777 msgid "Received SysEx"
5878 msgstr "SysEx recibido"
5979
60 #: src/elektroid.c:535 src/elektroid.c:635
80 #: src/elektroid.c:662 src/elektroid.c:753
6181 msgid "SysEx Files"
6282 msgstr "Archivos SysEx"
6383
64 #: src/elektroid.c:626
84 #: src/elektroid.c:696
85 #, c-format
86 msgid "Error while saving “%s”: %s."
87 msgstr "Error al guardar «%s»: %s."
88
89 #: src/elektroid.c:744
6590 msgid "Open SysEx"
6691 msgstr "Abrir SysEx"
6792
68 #: src/elektroid.c:631
93 #: src/elektroid.c:749
6994 msgid "_Open"
7095 msgstr "_Abrir"
7196
72 #: src/elektroid.c:659
97 #: src/elektroid.c:770
98 #, c-format
99 msgid "Error while loading “%s”: %s."
100 msgstr "Error al cargar «%s»: %s."
101
102 #: src/elektroid.c:780
73103 msgid "Send SysEx"
74104 msgstr "Enviar SysEx"
75105
76 #: src/elektroid.c:779
106 #: src/elektroid.c:882
77107 #, c-format
78108 msgid "Error while deleting “%s”: %s."
79109 msgstr "Error al eliminar «%s»: %s."
80110
81 #: src/elektroid.c:811
111 #: src/elektroid.c:914
82112 msgid "Are you sure you want to delete the selected items?"
83113 msgstr "¿Está seguro de que quiere eliminar los elementos seleccionados?"
84114
85 #: src/elektroid.c:813
115 #: src/elektroid.c:916
86116 msgid "_Delete"
87117 msgstr "_Eliminar"
88118
89 #: src/elektroid.c:867 res/gui.glade:106 res/gui.glade:155
119 #: src/elektroid.c:969 res/gui.glade:130 res/gui.glade:193
90120 msgid "Rename"
91121 msgstr "Renombrar"
92122
93 #: src/elektroid.c:885
123 #: src/elektroid.c:987
94124 #, c-format
95125 msgid "Error while renaming to “%s”: %s."
96126 msgstr "Error al renombrar a «%s»: %s."
97127
98 #: src/elektroid.c:1617 res/gui.glade:445 res/gui.glade:628
128 #: src/elektroid.c:1550 res/gui.glade:121 res/gui.glade:183 res/gui.glade:184
99129 msgid "Add Directory"
100130 msgstr "Añadir directorio"
101131
102 #: src/elektroid.c:1635
132 #: src/elektroid.c:1568
103133 #, c-format
104134 msgid "Error while creating dir “%s”: %s."
105135 msgstr "Error al crear el directorio «%s»: %s."
106136
107 #: src/elektroid.c:1797
137 #: src/elektroid.c:1640
108138 msgid "Queued"
109139 msgstr "Encolada"
110140
111 #: src/elektroid.c:1799
141 #: src/elektroid.c:1642
112142 msgid "Running"
113143 msgstr "Ejecutando"
114144
115 #: src/elektroid.c:1801
145 #: src/elektroid.c:1644
116146 msgid "Completed"
117147 msgstr "Completada"
118148
119 #: src/elektroid.c:1803
149 #: src/elektroid.c:1646
120150 msgid "Completed with errors"
121151 msgstr "Completada con errores"
122152
123 #: src/elektroid.c:1805
153 #: src/elektroid.c:1648
124154 msgid "Canceled"
125155 msgstr "Cancelada"
126156
127 #: src/elektroid.c:1807 src/elektroid.c:1821
128 msgid "Undefined"
129 msgstr "Indefinido"
130
131 #: src/elektroid.c:1817
157 #: src/elektroid.c:1660
132158 msgid "Upload"
133159 msgstr "Carga"
134160
135 #: src/elektroid.c:1819
161 #: src/elektroid.c:1662
136162 msgid "Download"
137163 msgstr "Descarga"
138164
139 #: src/elektroid.c:2613 src/elektroid.c:2643
165 #: src/elektroid.c:2518 src/elektroid.c:2559
140166 #, c-format
141167 msgid "Error while moving from “%s” to “%s”: %s."
142168 msgstr "Error al mover de «%s» a «%s»: %s."
143169
144 #: res/gui.glade:55
170 #: res/gui.glade:70
145171 msgid "Upload Selection"
146172 msgstr "Cargar selección"
147173
148 #: res/gui.glade:70
174 #: res/gui.glade:85
149175 msgid "Play"
150176 msgstr "Reproducir"
151177
152 #: res/gui.glade:84
178 #: res/gui.glade:99
153179 msgid "Open With External Editor"
154180 msgstr "Abrir con editor externo"
155181
156 #: res/gui.glade:92
182 #: res/gui.glade:107
157183 msgid "Show in File Manager"
158184 msgstr "Mostrar en gestor de archivos"
159185
160 #: res/gui.glade:115 res/gui.glade:164
186 #: res/gui.glade:139 res/gui.glade:202
161187 msgid "Delete"
162188 msgstr "Eliminar"
163189
164 #: res/gui.glade:140
190 #: res/gui.glade:168
165191 msgid "Download Selection"
166192 msgstr "Descargar selección"
167193
168 #: res/gui.glade:196
169 msgid "GNU/Linux sample transfer application for Elektron devices"
170 msgstr ""
171 "Aplicación GNU/Linux de transferencia de muestras para dispositivos Elektron"
172
173 #: res/gui.glade:199
194 #: res/gui.glade:238
195 msgid "GNU/Linux transfer application for Elektron devices"
196 msgstr "Aplicación GNU/Linux de transferencia para dispositivos Elektron"
197
198 #: res/gui.glade:241
174199 msgid "translator-credits"
175200 msgstr "David García Goñi <dagargo@gmail.com>"
176201
177 #: res/gui.glade:250
202 #: res/gui.glade:289
178203 msgid "_Receive SysEx"
179204 msgstr "_Recibir SysEx"
180205
181 #: res/gui.glade:263
206 #: res/gui.glade:302
182207 msgid "_Send SysEx"
183208 msgstr "_Enviar SysEx"
184209
185 #: res/gui.glade:287
210 #: res/gui.glade:326
186211 msgid "OS _Upgrade"
187212 msgstr "Actualizar _SO"
188213
189 #: res/gui.glade:311
214 #: res/gui.glade:350
190215 msgid "_About"
191216 msgstr "_Acerca de"
192217
193 #: res/gui.glade:424 res/gui.glade:607
218 #: res/gui.glade:434 res/gui.glade:583
194219 msgid "Go to Parent Directory"
195220 msgstr "Ir al directorio padre"
196221
197 #: res/gui.glade:466 res/gui.glade:649
222 #: res/gui.glade:455 res/gui.glade:604
198223 msgid "Refresh Directory"
199224 msgstr "Actualizar directorio"
200225
201 #: res/gui.glade:530 res/gui.glade:713 res/gui.glade:1336
226 #: res/gui.glade:512 res/gui.glade:671 res/gui.glade:1362
202227 msgid "Name"
203228 msgstr "Nombre"
204229
205 #: res/gui.glade:544 res/gui.glade:727
230 #: res/gui.glade:526 res/gui.glade:685
206231 msgid "Size"
207232 msgstr "Tamaño"
208233
209 #: res/gui.glade:780
234 #: res/gui.glade:738
210235 msgid "Refresh Devices"
211236 msgstr "Actualizar dispositivos"
212237
213238 #. It is recommended to split the text in two lines if it is too long
214 #: res/gui.glade:860
239 #: res/gui.glade:856
215240 msgid "Auto play"
216241 msgstr ""
217242 "Reproducción\n"
218243 "automática"
219244
220 #: res/gui.glade:1092
245 #: res/gui.glade:1088
221246 msgid "Status"
222247 msgstr "Estado"
223248
224 #: res/gui.glade:1103
249 #: res/gui.glade:1099
225250 msgid "Type"
226251 msgstr "Tipo"
227252
228 #: res/gui.glade:1114
253 #: res/gui.glade:1120
229254 msgid "Source"
230255 msgstr "Origen"
231256
232 #: res/gui.glade:1128
257 #: res/gui.glade:1134
233258 msgid "Destination"
234259 msgstr "Destino"
235260
236 #: res/gui.glade:1143
261 #: res/gui.glade:1149
237262 msgid "Progress"
238263 msgstr "Progreso"
239264
240 #: res/gui.glade:1175
265 #: res/gui.glade:1181
241266 msgid "Cancel Tasks"
242267 msgstr "Cancelar tareas"
243268
244 #: res/gui.glade:1196
269 #: res/gui.glade:1202
245270 msgid "Remove Queued Tasks"
246271 msgstr "Eliminar tareas encoladas"
247272
248 #: res/gui.glade:1217
273 #: res/gui.glade:1223
249274 msgid "Clear Finished Tasks"
250275 msgstr "Limpiar tareas terminadas"
00 # French GUI translation for Elektroid.
1 # Copyright (C) 2019-2020 Olivier Humbert
1 # Copyright (C) 2019-2021 Olivier Humbert
22 # This file is distributed under the same license as the Elektroid package.
3 # Olivier Humbert <trebmuh@tuxfamily.org>, 2019-2020.
3 # Olivier Humbert <trebmuh@tuxfamily.org>, 2019-2021.
44 #
55 msgid ""
66 msgstr ""
7 "Project-Id-Version: elektroid 1.4\n"
7 "Project-Id-Version: elektroid 2.0\n"
88 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2021-06-20 17:23+0200\n"
10 "PO-Revision-Date: 2021-01-05 17:59+0100\n"
9 "POT-Creation-Date: 2021-12-01 18:58+0100\n"
10 "PO-Revision-Date: 2021-12-03 17:59+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:275
19 #: src/elektroid.c:249
20 msgid "Samples"
21 msgstr "Échantillons"
22
23 #: src/elektroid.c:251
24 msgid "Presets"
25 msgstr "Préréglages"
26
27 #: src/elektroid.c:253
28 msgid "Projects"
29 msgstr "Projets"
30
31 #: src/elektroid.c:255
32 msgid "Sounds"
33 msgstr "Sons"
34
35 #: src/elektroid.c:257 src/elektroid.c:1650 src/elektroid.c:1664
36 msgid "Undefined"
37 msgstr "Indéfini"
38
39 #: src/elektroid.c:398
2040 #, c-format
2141 msgid "Connected to %s%s"
2242 msgstr "Connecté à %s%s"
2343
24 #: src/elektroid.c:283 src/elektroid.c:3172
44 #: src/elektroid.c:406 src/elektroid.c:3215
2545 msgid "Not connected"
2646 msgstr "Non connecté"
2747
28 #: src/elektroid.c:424
48 #: src/elektroid.c:549
2949 msgid "Waiting..."
3050 msgstr "En attente..."
3151
32 #: src/elektroid.c:427
52 #: src/elektroid.c:552
3353 msgid "Sending..."
3454 msgstr "Envoi en cours..."
3555
36 #: src/elektroid.c:431
56 #: src/elektroid.c:556
3757 msgid "Receiving..."
3858 msgstr "Réception en cours..."
3959
40 #: src/elektroid.c:499
60 #: src/elektroid.c:624
4161 msgid "Receive SysEx"
4262 msgstr "Réception de SysEx"
4363
44 #: src/elektroid.c:521
64 #: src/elektroid.c:648
4565 msgid "Save SysEx"
4666 msgstr "Sauvegarde de SysEx"
4767
48 #: src/elektroid.c:524 src/elektroid.c:629 src/elektroid.c:812
68 #: src/elektroid.c:651 src/elektroid.c:747 src/elektroid.c:915
4969 msgid "_Cancel"
5070 msgstr "_Annuler"
5171
52 #: src/elektroid.c:526
72 #: src/elektroid.c:653
5373 msgid "_Save"
5474 msgstr "_Sauvegarder"
5575
56 #: src/elektroid.c:530
76 #: src/elektroid.c:657
5777 msgid "Received SysEx"
5878 msgstr "SysEx reçu"
5979
60 #: src/elektroid.c:535 src/elektroid.c:635
80 #: src/elektroid.c:662 src/elektroid.c:753
6181 msgid "SysEx Files"
6282 msgstr "Fichiers SysEx"
6383
64 #: src/elektroid.c:626
84 #: src/elektroid.c:696
85 #, c-format
86 msgid "Error while saving “%s”: %s."
87 msgstr "Erreur lors de la sauvegarde de « %s » : %s."
88
89 #: src/elektroid.c:744
6590 msgid "Open SysEx"
6691 msgstr "Ouvrir SysEx"
6792
68 #: src/elektroid.c:631
93 #: src/elektroid.c:749
6994 msgid "_Open"
7095 msgstr "_Ouvrir"
7196
72 #: src/elektroid.c:659
97 #: src/elektroid.c:770
98 #, c-format
99 msgid "Error while loading “%s”: %s."
100 msgstr "Erreur lors du chargement de « %s » : %s."
101
102 #: src/elektroid.c:780
73103 msgid "Send SysEx"
74104 msgstr "Envoyer SysEx"
75105
76 #: src/elektroid.c:779
106 #: src/elektroid.c:882
77107 #, c-format
78108 msgid "Error while deleting “%s”: %s."
79109 msgstr "Erreur lors de la suppression de « %s » : %s."
80110
81 #: src/elektroid.c:811
111 #: src/elektroid.c:914
82112 msgid "Are you sure you want to delete the selected items?"
83113 msgstr "Souhaitez-vous vraiment supprimer les éléments sélectionnés ?"
84114
85 #: src/elektroid.c:813
115 #: src/elektroid.c:916
86116 msgid "_Delete"
87117 msgstr "_Supprimer"
88118
89 #: src/elektroid.c:867 res/gui.glade:106 res/gui.glade:155
119 #: src/elektroid.c:969 res/gui.glade:130 res/gui.glade:193
90120 msgid "Rename"
91121 msgstr "Renommer"
92122
93 #: src/elektroid.c:885
123 #: src/elektroid.c:987
94124 #, c-format
95125 msgid "Error while renaming to “%s”: %s."
96126 msgstr "Erreur lors du renommage de « %s » : %s."
97127
98 #: src/elektroid.c:1617 res/gui.glade:445 res/gui.glade:628
128 #: src/elektroid.c:1550 res/gui.glade:121 res/gui.glade:183 res/gui.glade:184
99129 msgid "Add Directory"
100130 msgstr "Ajout d'un répertoire"
101131
102 #: src/elektroid.c:1635
132 #: src/elektroid.c:1568
103133 #, c-format
104134 msgid "Error while creating dir “%s”: %s."
105135 msgstr "Erreur lors de la création du répertoire « %s » : %s."
106136
107 #: src/elektroid.c:1797
137 #: src/elektroid.c:1640
108138 msgid "Queued"
109 msgstr "Mise en fil d'attente"
110
111 #: src/elektroid.c:1799
139 msgstr "Mise en file d'attente"
140
141 #: src/elektroid.c:1642
112142 msgid "Running"
113143 msgstr "En cours"
114144
115 #: src/elektroid.c:1801
145 #: src/elektroid.c:1644
116146 msgid "Completed"
117147 msgstr "Terminé"
118148
119 #: src/elektroid.c:1803
149 #: src/elektroid.c:1646
120150 msgid "Completed with errors"
121151 msgstr "Terminé avec des erreurs"
122152
123 #: src/elektroid.c:1805
153 #: src/elektroid.c:1648
124154 msgid "Canceled"
125155 msgstr "Annulé"
126156
127 #: src/elektroid.c:1807 src/elektroid.c:1821
128 msgid "Undefined"
129 msgstr "Indéfini"
130
131 #: src/elektroid.c:1817
157 #: src/elektroid.c:1660
132158 msgid "Upload"
133159 msgstr "Téléversement"
134160
135 #: src/elektroid.c:1819
161 #: src/elektroid.c:1662
136162 msgid "Download"
137163 msgstr "Téléchargement"
138164
139 #: src/elektroid.c:2613 src/elektroid.c:2643
165 #: src/elektroid.c:2518 src/elektroid.c:2559
140166 #, c-format
141167 msgid "Error while moving from “%s” to “%s”: %s."
142168 msgstr "Erreur lors du passage de « %s » à « %s » : %s."
143169
144 #: res/gui.glade:55
170 #: res/gui.glade:70
145171 msgid "Upload Selection"
146172 msgstr "Téléversement de la sélection"
147173
148 #: res/gui.glade:70
174 #: res/gui.glade:85
149175 msgid "Play"
150176 msgstr "Lecture"
151177
152 #: res/gui.glade:84
178 #: res/gui.glade:99
153179 msgid "Open With External Editor"
154180 msgstr "Ouvrir avec un éditeur externe"
155181
156 #: res/gui.glade:92
182 #: res/gui.glade:107
157183 msgid "Show in File Manager"
158184 msgstr "Afficher dans un ge_stionnaire de fichier"
159185
160 #: res/gui.glade:115 res/gui.glade:164
186 #: res/gui.glade:139 res/gui.glade:202
161187 msgid "Delete"
162188 msgstr "Supprimer"
163189
164 #: res/gui.glade:140
190 #: res/gui.glade:168
165191 msgid "Download Selection"
166192 msgstr "Téléchargement de la sélection"
167193
168 #: res/gui.glade:196
169 msgid "GNU/Linux sample transfer application for Elektron devices"
170 msgstr ""
171 "Application GNU/Linux de transfert d'échantillon pour les périphériques "
172 "Elektron"
173
174 #: res/gui.glade:199
194 #: res/gui.glade:238
195 msgid "GNU/Linux transfer application for Elektron devices"
196 msgstr "Application GNU/Linux de transfert pour les périphériques Elektron"
197
198 #: res/gui.glade:241
175199 msgid "translator-credits"
176200 msgstr "Olivier Humbert <trebmuh@tuxfamily.org>"
177201
178 #: res/gui.glade:250
202 #: res/gui.glade:289
179203 msgid "_Receive SysEx"
180204 msgstr "_Réception de SysEx"
181205
182 #: res/gui.glade:263
206 #: res/gui.glade:302
183207 msgid "_Send SysEx"
184208 msgstr "Envoi de _Sysex"
185209
186 #: res/gui.glade:287
210 #: res/gui.glade:326
187211 msgid "OS _Upgrade"
188212 msgstr "Mise à jo_ur SE"
189213
190 #: res/gui.glade:311
214 #: res/gui.glade:350
191215 msgid "_About"
192216 msgstr "À _propos"
193217
194 #: res/gui.glade:424 res/gui.glade:607
218 #: res/gui.glade:434 res/gui.glade:583
195219 msgid "Go to Parent Directory"
196220 msgstr "Aller au répertoire parent"
197221
198 #: res/gui.glade:466 res/gui.glade:649
222 #: res/gui.glade:455 res/gui.glade:604
199223 msgid "Refresh Directory"
200224 msgstr "Rafraîchir le répertoire"
201225
202 #: res/gui.glade:530 res/gui.glade:713 res/gui.glade:1336
226 #: res/gui.glade:512 res/gui.glade:671 res/gui.glade:1362
203227 msgid "Name"
204228 msgstr "Nom"
205229
206 #: res/gui.glade:544 res/gui.glade:727
230 #: res/gui.glade:526 res/gui.glade:685
207231 msgid "Size"
208232 msgstr "Taille"
209233
210 #: res/gui.glade:780
234 #: res/gui.glade:738
211235 msgid "Refresh Devices"
212236 msgstr "Rafraîchir les périphériques"
213237
214238 #. It is recommended to split the text in two lines if it is too long
215 #: res/gui.glade:860
239 #: res/gui.glade:856
216240 msgid "Auto play"
217241 msgstr ""
218242 "Lecture\n"
219243 "automatique"
220244
221 #: res/gui.glade:1092
245 #: res/gui.glade:1088
222246 msgid "Status"
223247 msgstr "Statut"
224248
225 #: res/gui.glade:1103
249 #: res/gui.glade:1099
226250 msgid "Type"
227251 msgstr "Type"
228252
229 #: res/gui.glade:1114
253 #: res/gui.glade:1120
230254 msgid "Source"
231255 msgstr "Source"
232256
233 #: res/gui.glade:1128
257 #: res/gui.glade:1134
234258 msgid "Destination"
235259 msgstr "Destination"
236260
237 #: res/gui.glade:1143
261 #: res/gui.glade:1149
238262 msgid "Progress"
239263 msgstr "Progrès"
240264
241 #: res/gui.glade:1175
265 #: res/gui.glade:1181
242266 msgid "Cancel Tasks"
243267 msgstr "Annuler les tâches"
244268
245 #: res/gui.glade:1196
269 #: res/gui.glade:1202
246270 msgid "Remove Queued Tasks"
247 msgstr "Supprimer des tâches dans la file d'attente"
248
249 #: res/gui.glade:1217
271 msgstr "Supprimer les tâches dans la file d'attente"
272
273 #: res/gui.glade:1223
250274 msgid "Clear Finished Tasks"
251275 msgstr "Nettoyer les tâches terminées"
0 # elektroid Brazilian Portuguese translation
1 # Copyright (C) 2021 David García Goñi
2 # This file is distributed under the same license as the elektroid package.
3 # Gustavo Costa <xfgusta@gmail.com>, 2021.
4 #
5 msgid ""
6 msgstr ""
7 "Project-Id-Version: elektroid 1.4\n"
8 "Report-Msgid-Bugs-To: dagargo@gmail.com\n"
9 "POT-Creation-Date: 2021-12-01 18:58+0100\n"
10 "PO-Revision-Date: 2021-12-01 17:56-0300\n"
11 "Last-Translator: Gustavo Costa <xfgusta@gmail.com>\n"
12 "Language-Team: \n"
13 "Language: pt_BR\n"
14 "MIME-Version: 1.0\n"
15 "Content-Type: text/plain; charset=UTF-8\n"
16 "Content-Transfer-Encoding: 8bit\n"
17 "X-Generator: Poedit 3.0\n"
18 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
19
20 #: src/elektroid.c:249
21 msgid "Samples"
22 msgstr "Samples"
23
24 #: src/elektroid.c:251
25 msgid "Presets"
26 msgstr "Presets"
27
28 #: src/elektroid.c:253
29 msgid "Projects"
30 msgstr "Projects"
31
32 #: src/elektroid.c:255
33 msgid "Sounds"
34 msgstr "Sounds"
35
36 #: src/elektroid.c:257 src/elektroid.c:1650 src/elektroid.c:1664
37 msgid "Undefined"
38 msgstr "Indefinido"
39
40 #: src/elektroid.c:398
41 #, c-format
42 msgid "Connected to %s%s"
43 msgstr "Conectado a %s%s"
44
45 #: src/elektroid.c:406 src/elektroid.c:3215
46 msgid "Not connected"
47 msgstr "Não conectado"
48
49 #: src/elektroid.c:549
50 msgid "Waiting..."
51 msgstr "Esperando..."
52
53 #: src/elektroid.c:552
54 msgid "Sending..."
55 msgstr "Enviando..."
56
57 #: src/elektroid.c:556
58 msgid "Receiving..."
59 msgstr "Recebendo..."
60
61 #: src/elektroid.c:624
62 msgid "Receive SysEx"
63 msgstr "Receber SysEx"
64
65 #: src/elektroid.c:648
66 msgid "Save SysEx"
67 msgstr "Salvar SysEx"
68
69 #: src/elektroid.c:651 src/elektroid.c:747 src/elektroid.c:915
70 msgid "_Cancel"
71 msgstr "_Cancelar"
72
73 #: src/elektroid.c:653
74 msgid "_Save"
75 msgstr "_Salvar"
76
77 #: src/elektroid.c:657
78 msgid "Received SysEx"
79 msgstr "SysEx recebido"
80
81 #: src/elektroid.c:662 src/elektroid.c:753
82 msgid "SysEx Files"
83 msgstr "Arquivos SysEx"
84
85 #: src/elektroid.c:696
86 #, c-format
87 msgid "Error while saving “%s”: %s."
88 msgstr "Erro ao excluir \"%s\": %s."
89
90 #: src/elektroid.c:744
91 msgid "Open SysEx"
92 msgstr "Abrir SysEx"
93
94 #: src/elektroid.c:749
95 msgid "_Open"
96 msgstr "_Abrir"
97
98 #: src/elektroid.c:770
99 #, c-format
100 msgid "Error while loading “%s”: %s."
101 msgstr "Erro ao excluir \"%s\": %s."
102
103 #: src/elektroid.c:780
104 msgid "Send SysEx"
105 msgstr "Enviar SysEx"
106
107 #: src/elektroid.c:882
108 #, c-format
109 msgid "Error while deleting “%s”: %s."
110 msgstr "Erro ao excluir \"%s\": %s."
111
112 #: src/elektroid.c:914
113 msgid "Are you sure you want to delete the selected items?"
114 msgstr "Tem certeza de que deseja excluir os itens selecionados?"
115
116 #: src/elektroid.c:916
117 msgid "_Delete"
118 msgstr "_Excluir"
119
120 #: src/elektroid.c:969 res/gui.glade:130 res/gui.glade:193
121 msgid "Rename"
122 msgstr "Renomar"
123
124 #: src/elektroid.c:987
125 #, c-format
126 msgid "Error while renaming to “%s”: %s."
127 msgstr "Erro ao renomear para \"%s\": %s."
128
129 #: src/elektroid.c:1550 res/gui.glade:121 res/gui.glade:183 res/gui.glade:184
130 msgid "Add Directory"
131 msgstr "Adicionar diretório"
132
133 #: src/elektroid.c:1568
134 #, c-format
135 msgid "Error while creating dir “%s”: %s."
136 msgstr "Erro ao criar diretório \"%s\": %s."
137
138 #: src/elektroid.c:1640
139 msgid "Queued"
140 msgstr "Na fila"
141
142 #: src/elektroid.c:1642
143 msgid "Running"
144 msgstr "Executando"
145
146 #: src/elektroid.c:1644
147 msgid "Completed"
148 msgstr "Completado"
149
150 #: src/elektroid.c:1646
151 msgid "Completed with errors"
152 msgstr "Completado com erros"
153
154 #: src/elektroid.c:1648
155 msgid "Canceled"
156 msgstr "Cancelado"
157
158 #: src/elektroid.c:1660
159 msgid "Upload"
160 msgstr "Upload"
161
162 #: src/elektroid.c:1662
163 msgid "Download"
164 msgstr "Download"
165
166 #: src/elektroid.c:2518 src/elektroid.c:2559
167 #, c-format
168 msgid "Error while moving from “%s” to “%s”: %s."
169 msgstr "Erro ao mover \"%s\" para \"%s\": %s."
170
171 #: res/gui.glade:70
172 msgid "Upload Selection"
173 msgstr "Seleção de upload"
174
175 #: res/gui.glade:85
176 msgid "Play"
177 msgstr "Reproduzir"
178
179 #: res/gui.glade:99
180 msgid "Open With External Editor"
181 msgstr "Abrir com um editor externo"
182
183 #: res/gui.glade:107
184 msgid "Show in File Manager"
185 msgstr "Mostrar no gerenciador de arquivos"
186
187 #: res/gui.glade:139 res/gui.glade:202
188 msgid "Delete"
189 msgstr "Excluir"
190
191 #: res/gui.glade:168
192 msgid "Download Selection"
193 msgstr "Seleção de download"
194
195 #: res/gui.glade:238
196 msgid "GNU/Linux transfer application for Elektron devices"
197 msgstr "Aplicativo GNU/Linux de transferência para dispositivos Elektron"
198
199 #: res/gui.glade:241
200 msgid "translator-credits"
201 msgstr "Gustavo Costa <xfgusta@gmail.com>"
202
203 #: res/gui.glade:289
204 msgid "_Receive SysEx"
205 msgstr "_Receber SysEx"
206
207 #: res/gui.glade:302
208 msgid "_Send SysEx"
209 msgstr "_Enviar SysEx"
210
211 #: res/gui.glade:326
212 msgid "OS _Upgrade"
213 msgstr "Atualizar _OS"
214
215 #: res/gui.glade:350
216 msgid "_About"
217 msgstr "_Sobre"
218
219 #: res/gui.glade:434 res/gui.glade:583
220 msgid "Go to Parent Directory"
221 msgstr "Ir para o diretório pai"
222
223 #: res/gui.glade:455 res/gui.glade:604
224 msgid "Refresh Directory"
225 msgstr "Atualizar diretório"
226
227 #: res/gui.glade:512 res/gui.glade:671 res/gui.glade:1362
228 msgid "Name"
229 msgstr "Nome"
230
231 #: res/gui.glade:526 res/gui.glade:685
232 msgid "Size"
233 msgstr "Tamanho"
234
235 #: res/gui.glade:738
236 msgid "Refresh Devices"
237 msgstr "Atualizar dispositivos"
238
239 #. It is recommended to split the text in two lines if it is too long
240 #: res/gui.glade:856
241 msgid "Auto play"
242 msgstr "Reprodução automática"
243
244 #: res/gui.glade:1088
245 msgid "Status"
246 msgstr "Status"
247
248 #: res/gui.glade:1099
249 msgid "Type"
250 msgstr "Tipo"
251
252 #: res/gui.glade:1120
253 msgid "Source"
254 msgstr "Origem"
255
256 #: res/gui.glade:1134
257 msgid "Destination"
258 msgstr "Destino"
259
260 #: res/gui.glade:1149
261 msgid "Progress"
262 msgstr "Progresso"
263
264 #: res/gui.glade:1181
265 msgid "Cancel Tasks"
266 msgstr "Cancelar tarefas"
267
268 #: res/gui.glade:1202
269 msgid "Remove Queued Tasks"
270 msgstr "Remover tarefas em fila"
271
272 #: res/gui.glade:1223
273 msgid "Clear Finished Tasks"
274 msgstr "Limpar tarefas concluídas"
77 metainfo_DATA = elektroid.appdata.xml
88
99 svgicondir = $(datarootdir)/icons/hicolor/scalable/apps
10 svgicon_DATA = elektroid.svg elektroid-symbolic.svg elektroid-wave-symbolic.svg elektroid-pattern-symbolic.svg
10 svgicon_DATA = elektroid.svg elektroid-symbolic.svg elektroid-wave-symbolic.svg elektroid-data-symbolic.svg elektroid-project-symbolic.svg elektroid-sound-symbolic.svg
1111
1212 gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datarootdir)/icons/hicolor
1313
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
-198
res/elektroid-pattern-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-project-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="3.8465541"
31 inkscape:cy="6.6917158"
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.2000223;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
86 id="rect1509-3-3"
87 width="4.2333331"
88 height="0.26458174"
89 x="0"
90 y="293.29584" />
91 <rect
92 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.2000223;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
93 id="rect1509-3-3-3"
94 width="4.2333331"
95 height="0.26458174"
96 x="6.8992989e-08"
97 y="296.20627" />
98 <rect
99 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.15813068;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
100 id="rect1509-5-3-5-1"
101 width="0.26458031"
102 height="2.6458194"
103 x="2.9897915e-06"
104 y="293.56042" />
105 <rect
106 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.15813071;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
107 id="rect1509-5-3-5-1-4"
108 width="0.26458031"
109 height="2.6458209"
110 x="3.9687529"
111 y="293.56042" />
112 <rect
113 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.18710373;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
114 id="rect1509-3-3-3-9"
115 width="3.7041667"
116 height="0.26458174"
117 x="0.26458332"
118 y="295.41251" />
119 <rect
120 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071882;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
121 id="rect1509-5-5-2-3-0-9-7-6"
122 width="0.26458332"
123 height="0.52916741"
124 x="0.79374999"
125 y="295.67709" />
126 <rect
127 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071882;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
128 id="rect1509-5-5-2-3-0-9-7-8"
129 width="0.26458332"
130 height="0.52916741"
131 x="1.5875"
132 y="295.67709" />
133 <rect
134 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071882;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
135 id="rect1509-5-5-2-3-0-9-7-9"
136 width="0.26458335"
137 height="0.52916741"
138 x="3.175"
139 y="295.67709" />
140 <rect
141 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071882;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
142 id="rect1509-5-5-2-3-0-9-7-9-2"
143 width="0.26458335"
144 height="0.52916741"
145 x="2.3812499"
146 y="295.67709" />
147 <rect
148 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661222;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
149 id="rect1509-5-5-2-3-0-9-7-6-6"
150 width="0.26458335"
151 height="0.79374588"
152 x="0.52916664"
153 y="293.56042" />
154 <rect
155 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.18709567;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
156 id="rect1509-3-3-3-9-0"
157 width="3.7041664"
158 height="0.26455897"
159 x="0.26458335"
160 y="294.61874" />
161 <rect
162 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071882;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
163 id="rect1509-5-5-2-3-0-9-7-6-4"
164 width="0.26458332"
165 height="0.52916741"
166 x="0.79374999"
167 y="294.88333" />
168 <rect
169 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071882;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
170 id="rect1509-5-5-2-3-0-9-7-8-8"
171 width="0.26458332"
172 height="0.52916741"
173 x="1.5874999"
174 y="294.88333" />
175 <rect
176 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071882;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
177 id="rect1509-5-5-2-3-0-9-7-9-7"
178 width="0.26458335"
179 height="0.52916741"
180 x="3.175"
181 y="294.88333" />
182 <rect
183 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071882;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
184 id="rect1509-5-5-2-3-0-9-7-9-2-1"
185 width="0.26458335"
186 height="0.52916741"
187 x="2.3812499"
188 y="294.88333" />
189 <rect
190 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000452;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
191 id="rect1509-5-5-2-3-0-9-7-6-6-7"
192 width="0.26458335"
193 height="0.26457071"
194 x="0.26458332"
195 y="293.82501" />
196 <rect
197 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661222;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
198 id="rect1509-5-5-2-3-0-9-7-6-6-2"
199 width="0.26458335"
200 height="0.79374588"
201 x="3.4395831"
202 y="293.56042" />
203 <rect
204 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000452;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
205 id="rect1509-5-5-2-3-0-9-7-6-6-7-7"
206 width="0.26458335"
207 height="0.26457071"
208 x="3.175"
209 y="293.82501" />
210 <rect
211 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661222;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
212 id="rect1509-5-5-2-3-0-9-7-6-6-22"
213 width="0.26458335"
214 height="0.79374588"
215 x="2.9104166"
216 y="293.56042" />
217 <rect
218 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000452;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
219 id="rect1509-5-5-2-3-0-9-7-6-6-7-6"
220 width="0.26458335"
221 height="0.26457071"
222 x="2.6458333"
223 y="293.82501" />
224 <rect
225 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661222;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
226 id="rect1509-5-5-2-3-0-9-7-6-6-1"
227 width="0.26458335"
228 height="0.79374588"
229 x="2.3812499"
230 y="293.56042" />
231 <rect
232 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000452;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
233 id="rect1509-5-5-2-3-0-9-7-6-6-7-0"
234 width="0.26458335"
235 height="0.26457071"
236 x="0.79374993"
237 y="293.82504" />
238 <rect
239 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661222;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
240 id="rect1509-5-5-2-3-0-9-7-6-6-1-5"
241 width="0.26458335"
242 height="0.79374588"
243 x="1.0583333"
244 y="293.56042" />
245 <rect
246 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000452;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
247 id="rect1509-5-5-2-3-0-9-7-6-6-7-7-4"
248 width="0.26458335"
249 height="0.26457071"
250 x="3.7041664"
251 y="293.82501" />
252 <rect
253 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001405;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
254 id="rect1509-5-5-2-3-0-9-7-6-4-9"
255 width="1.0583333"
256 height="0.26459709"
257 x="0.26458338"
258 y="294.35416" />
259 <rect
260 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.12216524;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
261 id="rect1509-5-5-2-3-0-9-7-6-4-0"
262 width="1.5792319"
263 height="0.26456657"
264 x="2.3812499"
265 y="294.35416" />
266 </g>
267 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <svg
2 xmlns:dc="http://purl.org/dc/elements/1.1/"
3 xmlns:cc="http://creativecommons.org/ns#"
4 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
5 xmlns:svg="http://www.w3.org/2000/svg"
6 xmlns="http://www.w3.org/2000/svg"
7 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
8 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
9 width="16"
10 height="16"
11 viewBox="0 0 4.233333 4.2333333"
12 version="1.1"
13 id="svg924"
14 sodipodi:docname="elektroid-sound-symbolic.svg"
15 inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
16 <title
17 id="title2309">elektroid pattern symbolic</title>
18 <defs
19 id="defs918" />
20 <sodipodi:namedview
21 id="base"
22 pagecolor="#ffffff"
23 bordercolor="#666666"
24 borderopacity="1.0"
25 inkscape:pageopacity="0.0"
26 inkscape:pageshadow="2"
27 inkscape:zoom="32"
28 inkscape:cx="7.0754366"
29 inkscape:cy="5.4255657"
30 inkscape:document-units="px"
31 inkscape:current-layer="layer1"
32 showgrid="true"
33 inkscape:window-width="1680"
34 inkscape:window-height="1013"
35 inkscape:window-x="0"
36 inkscape:window-y="0"
37 inkscape:window-maximized="1"
38 inkscape:pagecheckerboard="false"
39 inkscape:document-rotation="0">
40 <inkscape:grid
41 type="xygrid"
42 id="grid1511" />
43 </sodipodi:namedview>
44 <metadata
45 id="metadata921">
46 <rdf:RDF>
47 <cc:Work
48 rdf:about="">
49 <dc:format>image/svg+xml</dc:format>
50 <dc:type
51 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
52 <dc:title>elektroid pattern symbolic</dc:title>
53 <cc:license
54 rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
55 <dc:creator>
56 <cc:Agent>
57 <dc:title>David García Goñi</dc:title>
58 </cc:Agent>
59 </dc:creator>
60 </cc:Work>
61 <cc:License
62 rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
63 <cc:permits
64 rdf:resource="http://creativecommons.org/ns#Reproduction" />
65 <cc:permits
66 rdf:resource="http://creativecommons.org/ns#Distribution" />
67 <cc:requires
68 rdf:resource="http://creativecommons.org/ns#Notice" />
69 <cc:requires
70 rdf:resource="http://creativecommons.org/ns#Attribution" />
71 <cc:permits
72 rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
73 <cc:requires
74 rdf:resource="http://creativecommons.org/ns#ShareAlike" />
75 </cc:License>
76 </rdf:RDF>
77 </metadata>
78 <g
79 inkscape:label="Capa 1"
80 inkscape:groupmode="layer"
81 id="layer1"
82 transform="translate(0,-292.76667)">
83 <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"
100 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"
135 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"
157 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)" />
373 </g>
374 </svg>
00 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!-- Created with Inkscape (http://www.inkscape.org/) -->
2
31 <svg
42 xmlns:dc="http://purl.org/dc/elements/1.1/"
53 xmlns:cc="http://creativecommons.org/ns#"
1412 version="1.1"
1513 id="svg924"
1614 sodipodi:docname="elektroid-symbolic.svg"
17 inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
15 inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
1816 <title
1917 id="title2309">elektroid wave symbolic</title>
2018 <defs
21 id="defs918" />
19 id="defs918">
20 <marker
21 style="overflow:visible"
22 id="DotL"
23 refX="0.0"
24 refY="0.0"
25 orient="auto"
26 inkscape:stockid="DotL"
27 inkscape:isstock="true">
28 <path
29 transform="scale(0.8) translate(7.4, 1)"
30 style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
31 d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
32 id="path1409" />
33 </marker>
34 </defs>
2235 <sodipodi:namedview
2336 id="base"
2437 pagecolor="#ffffff"
2639 borderopacity="1.0"
2740 inkscape:pageopacity="0.0"
2841 inkscape:pageshadow="2"
29 inkscape:zoom="32"
30 inkscape:cx="3.9542129"
31 inkscape:cy="7.2896177"
42 inkscape:zoom="45.254834"
43 inkscape:cx="8.5032133"
44 inkscape:cy="7.8849323"
3245 inkscape:document-units="px"
3346 inkscape:current-layer="layer1"
3447 showgrid="true"
3548 inkscape:window-width="1680"
36 inkscape:window-height="1023"
49 inkscape:window-height="1013"
3750 inkscape:window-x="0"
3851 inkscape:window-y="0"
3952 inkscape:window-maximized="1"
40 inkscape:pagecheckerboard="false">
53 inkscape:pagecheckerboard="false"
54 inkscape:document-rotation="0">
4155 <inkscape:grid
4256 type="xygrid"
4357 id="grid1511" />
8195 inkscape:groupmode="layer"
8296 id="layer1"
8397 transform="translate(0,-292.76667)">
84 <rect
85 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661125;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
86 id="rect1509-6-9-9-3-6"
87 width="0.26458332"
88 height="0.79372758"
89 x="0.52916664"
90 y="293.56042" />
91 <rect
92 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.13230319;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
93 id="rect1509-6-9-9-3-7"
94 width="0.26458332"
95 height="1.8520962"
96 x="0.79374999"
97 y="293.03125" />
98 <rect
99 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.11181602;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
100 id="rect1509-6-9-9-3-5"
101 width="0.26458332"
102 height="1.3229122"
103 x="1.0583334"
104 y="293.29584" />
105 <rect
106 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.11181567;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
107 id="rect1509-6-9-9-3-5-3"
108 width="0.26458332"
109 height="1.322904"
110 x="1.5875"
111 y="293.29587" />
112 <rect
113 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661211;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
114 id="rect1509-6-9-9-3-5-3-5"
115 width="0.26458332"
116 height="0.79374361"
117 x="2.1166666"
118 y="293.56042" />
119 <rect
120 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
121 id="rect1509-6-9-9-3-5-3-5-6"
122 width="0.26458332"
123 height="0.26457837"
124 x="2.6458333"
125 y="293.82501" />
126 <rect
127 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
128 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-2"
129 width="0.26458332"
130 height="0.26457837"
131 x="2.1166666"
132 y="294.35416" />
133 <rect
134 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
135 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-7"
136 width="0.26458332"
137 height="0.26457837"
138 x="2.1166666"
139 y="293.29581" />
140 <rect
141 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
142 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9"
143 width="0.26458332"
144 height="0.26457837"
145 x="1.5875"
146 y="294.61877" />
147 <rect
148 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.11181602;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
149 id="rect1509-6-9-9-3-5-0"
150 width="0.26458332"
151 height="1.3229122"
152 x="1.3229166"
153 y="293.29584" />
154 <rect
155 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661228;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
156 id="rect1509-6-9-9-3-5-3-6"
157 width="0.26458332"
158 height="0.79374689"
159 x="1.8520833"
160 y="293.56042" />
161 <rect
162 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000443;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
163 id="rect1509-6-9-9-3-5-3-5-2"
164 width="0.26458332"
165 height="0.26456958"
166 x="2.3812499"
167 y="293.82501" />
168 <rect
169 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661125;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
170 id="rect1509-6-9-9-3-6-1"
171 width="0.26458332"
172 height="0.79372758"
173 x="0.26458338"
174 y="293.56042" />
175 <rect
176 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
177 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-7"
178 width="0.26458332"
179 height="0.26457837"
180 x="1.3229166"
181 y="293.03125" />
182 <rect
183 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
184 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27"
185 width="0.26458332"
186 height="0.26457837"
187 x="1.3229166"
188 y="294.61874" />
189 <rect
190 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
191 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0"
192 width="0.26458332"
193 height="0.26457837"
194 x="1.0583333"
195 y="294.61874" />
196 <rect
197 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
198 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6"
199 width="0.26458332"
200 height="0.26457837"
201 x="1.5875"
202 y="293.03128" />
203 <rect
204 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
205 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-1"
206 width="0.26458332"
207 height="0.26457837"
208 x="1.0583333"
209 y="293.03125" />
210 <rect
211 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
212 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-7"
213 width="0.26458332"
214 height="0.26457837"
215 x="1.8520832"
216 y="294.35416" />
217 <rect
218 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
219 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-71"
220 width="0.26458332"
221 height="0.26457837"
222 x="1.8520832"
223 y="293.29584" />
224 <rect
225 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
226 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-7-7"
227 width="0.26458332"
228 height="0.26457837"
229 x="2.3812497"
230 y="294.08957" />
231 <rect
232 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
233 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-7-3"
234 width="0.26458332"
235 height="0.26457837"
236 x="2.3812497"
237 y="293.56039" />
238 <rect
239 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
240 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-7-6"
241 width="0.26458332"
242 height="0.26457837"
243 x="2.6458333"
244 y="293.56039" />
245 <rect
246 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
247 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-7-5"
248 width="0.26458332"
249 height="0.26457837"
250 x="2.6458333"
251 y="294.08957" />
252 <rect
253 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
254 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-5-6"
255 width="0.26458332"
256 height="0.26457837"
257 x="2.9104164"
258 y="293.56046" />
259 <rect
260 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
261 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-5-3"
262 width="0.26458332"
263 height="0.26457837"
264 x="2.9104164"
265 y="294.08963" />
266 <rect
267 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
268 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-9-9-85"
269 width="0.26458332"
270 height="0.26457837"
271 x="2.3812497"
272 y="293.29587" />
273 <rect
274 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
275 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-9-9-09"
276 width="0.26458332"
277 height="0.26457837"
278 x="2.3812497"
279 y="294.35422" />
280 <rect
281 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
282 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-7-6-6"
283 width="0.26458332"
284 height="0.26457837"
285 x="2.9104166"
286 y="293.82501" />
287 <rect
288 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661125;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
289 id="rect1509-6-9-9-3-6-3"
290 width="0.26458332"
291 height="0.79372758"
292 x="-3.7041664"
293 y="295.41251"
294 transform="scale(-1,1)" />
295 <rect
296 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.13230319;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
297 id="rect1509-6-9-9-3-7-6"
298 width="0.26458332"
299 height="1.8520962"
300 x="-3.4395831"
301 y="294.88333"
302 transform="scale(-1,1)" />
303 <rect
304 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.11181602;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
305 id="rect1509-6-9-9-3-5-7"
306 width="0.26458332"
307 height="1.3229122"
308 x="-3.1749997"
309 y="295.14792"
310 transform="scale(-1,1)" />
311 <rect
312 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.11181566;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
313 id="rect1509-6-9-9-3-5-3-53"
314 width="0.26458332"
315 height="1.322904"
316 x="-2.645833"
317 y="295.14795"
318 transform="scale(-1,1)" />
319 <rect
320 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661211;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
321 id="rect1509-6-9-9-3-5-3-5-5"
322 width="0.26458332"
323 height="0.79374361"
324 x="-2.1166666"
325 y="295.41251"
326 transform="scale(-1,1)" />
327 <rect
328 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
329 id="rect1509-6-9-9-3-5-3-5-6-6"
330 width="0.26458332"
331 height="0.26457837"
332 x="-1.5875"
333 y="295.67709"
334 transform="scale(-1,1)" />
335 <rect
336 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
337 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-2-2"
338 width="0.26458332"
339 height="0.26457837"
340 x="-2.1166666"
341 y="296.20624"
342 transform="scale(-1,1)" />
343 <rect
344 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
345 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-7-9"
346 width="0.26458332"
347 height="0.26457837"
348 x="-2.1166666"
349 y="295.14789"
350 transform="scale(-1,1)" />
351 <rect
352 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
353 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-1"
354 width="0.26458332"
355 height="0.26457837"
356 x="-2.645833"
357 y="296.47086"
358 transform="scale(-1,1)" />
359 <rect
360 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.11181602;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
361 id="rect1509-6-9-9-3-5-0-2"
362 width="0.26458332"
363 height="1.3229122"
364 x="-2.9104164"
365 y="295.14792"
366 transform="scale(-1,1)" />
367 <rect
368 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661228;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
369 id="rect1509-6-9-9-3-5-3-6-7"
370 width="0.26458332"
371 height="0.79374689"
372 x="-2.3812497"
373 y="295.41251"
374 transform="scale(-1,1)" />
375 <rect
376 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000443;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
377 id="rect1509-6-9-9-3-5-3-5-2-0"
378 width="0.26458332"
379 height="0.26456958"
380 x="-1.8520833"
381 y="295.67709"
382 transform="scale(-1,1)" />
383 <rect
384 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.08661125;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
385 id="rect1509-6-9-9-3-6-1-9"
386 width="0.26458332"
387 height="0.79372758"
388 x="-3.9687498"
389 y="295.41251"
390 transform="scale(-1,1)" />
391 <rect
392 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
393 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-7-3"
394 width="0.26458332"
395 height="0.26457837"
396 x="-2.9104164"
397 y="294.88333"
398 transform="scale(-1,1)" />
399 <rect
400 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
401 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-6"
402 width="0.26458332"
403 height="0.26457837"
404 x="-2.9104164"
405 y="296.47083"
406 transform="scale(-1,1)" />
407 <rect
408 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
409 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-0"
410 width="0.26458332"
411 height="0.26457837"
412 x="-3.1749997"
413 y="296.47083"
414 transform="scale(-1,1)" />
415 <rect
416 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
417 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-6"
418 width="0.26458332"
419 height="0.26457837"
420 x="-2.645833"
421 y="294.88336"
422 transform="scale(-1,1)" />
423 <rect
424 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
425 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-1-2"
426 width="0.26458332"
427 height="0.26457837"
428 x="-3.1749997"
429 y="294.88333"
430 transform="scale(-1,1)" />
431 <rect
432 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
433 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-7-6"
434 width="0.26458332"
435 height="0.26457837"
436 x="-2.3812499"
437 y="296.20624"
438 transform="scale(-1,1)" />
439 <rect
440 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
441 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-71-1"
442 width="0.26458332"
443 height="0.26457837"
444 x="-2.3812499"
445 y="295.14792"
446 transform="scale(-1,1)" />
447 <rect
448 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
449 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-7-7-8"
450 width="0.26458332"
451 height="0.26457837"
452 x="-1.8520836"
453 y="295.94165"
454 transform="scale(-1,1)" />
455 <rect
456 style="opacity:0.75;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
457 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-0-27-0-7-3-7"
458 width="0.26458332"
459 height="0.26457837"
460 x="-1.8520836"
461 y="295.41248"
462 transform="scale(-1,1)" />
463 <rect
464 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
465 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-7-6-9"
466 width="0.26458332"
467 height="0.26457837"
468 x="-1.5875"
469 y="295.41248"
470 transform="scale(-1,1)" />
471 <rect
472 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
473 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-7-5-2"
474 width="0.26458332"
475 height="0.26457837"
476 x="-1.5875"
477 y="295.94165"
478 transform="scale(-1,1)" />
479 <rect
480 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
481 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-5-6-0"
482 width="0.26458332"
483 height="0.26457837"
484 x="-1.3229169"
485 y="295.41254"
486 transform="scale(-1,1)" />
487 <rect
488 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
489 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-5-3-2"
490 width="0.26458332"
491 height="0.26457837"
492 x="-1.3229169"
493 y="295.94171"
494 transform="scale(-1,1)" />
495 <rect
496 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
497 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-9-9-85-3"
498 width="0.26458332"
499 height="0.26457837"
500 x="-1.8520836"
501 y="295.14795"
502 transform="scale(-1,1)" />
503 <rect
504 style="opacity:0.25;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
505 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-9-6-9-9-09-7"
506 width="0.26458332"
507 height="0.26457837"
508 x="-1.8520836"
509 y="296.2063"
510 transform="scale(-1,1)" />
511 <rect
512 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000526;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
513 id="rect1509-6-9-9-3-5-3-5-6-2-9-1-7-6-6-5"
514 width="0.26458332"
515 height="0.26457837"
516 x="-1.3229166"
517 y="295.67709"
518 transform="scale(-1,1)" />
98 <path
99 id="path838-7-5-7"
100 style="mix-blend-mode:normal;fill:#bebebe;fill-opacity:1;stroke:#bebebe;stroke-width:0;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
101 d="m 0.79374997,292.76667 0,0.79375 H 0 l -1.4375001e-8,1.05833 H 0.79374997 l 0,0.79375 2.38124993,-1.32291 z"
102 sodipodi:nodetypes="cccccccc" />
103 <path
104 id="path838-7-5-7-3"
105 style="fill:#bebebe;fill-opacity:1;stroke:#bebebe;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
106 d="M 3.4395832,294.35417 1.0583333,295.67709 3.4395832,297 v -0.79375 h 0.7937499 v -1.05833 H 3.4395832 Z"
107 sodipodi:nodetypes="cccccccc" />
519108 </g>
520109 </svg>
2727 inkscape:pageopacity="0.0"
2828 inkscape:pageshadow="2"
2929 inkscape:zoom="32"
30 inkscape:cx="9.8604629"
31 inkscape:cy="7.9458677"
30 inkscape:cx="-0.63389357"
31 inkscape:cy="7.6958677"
3232 inkscape:document-units="px"
3333 inkscape:current-layer="layer1"
3434 showgrid="true"
8282 id="layer1"
8383 transform="translate(0,-292.76667)">
8484 <rect
85 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.17322503;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
86 id="rect1509-6-9-6"
87 width="0.26458332"
88 height="3.1750035"
85 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.14143676;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
86 id="rect1509-6-9-3-6-0-2"
87 width="0.26458341"
88 height="2.1166418"
89 x="1.5875"
90 y="293.82501"
91 inkscape:transform-center-x="0.81558974"
92 inkscape:transform-center-y="-3.2084846" />
93 <rect
94 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.17322472;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
95 id="rect1509-6-9-3-6-0-8-9-4"
96 width="0.26458305"
97 height="3.1749952"
98 x="2.1166668"
99 y="293.29584"
100 inkscape:transform-center-x="0.81559079"
101 inkscape:transform-center-y="-4.8128001" />
102 <rect
103 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.14143814;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
104 id="rect1509-6-9-3-1-3-6-5-3"
105 width="0.52916664"
106 height="1.0583419"
107 x="2.9104166"
108 y="294.35416" />
109 <rect
110 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.26460543;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
111 id="rect1509-6-9-3-1-3-6-5-6"
112 width="0.5291667"
113 height="3.7041647"
114 x="0.52916664"
115 y="293.03125" />
116 <rect
117 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001156;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
118 id="rect1509-6-9-3-6-0-8-3"
119 width="0.2645832"
120 height="1.0583349"
121 x="3.7041664"
122 y="294.35416"
123 inkscape:transform-center-x="0.81558898"
124 inkscape:transform-center-y="-1.6042882" />
125 <rect
126 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071922;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
127 id="rect1509-6-9-6-8-2-2-9"
128 width="0.52916664"
129 height="0.26458672"
130 x="0.52916658"
131 y="292.76666" />
132 <rect
133 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071922;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
134 id="rect1509-6-9-6-8-2-2-1"
135 width="0.52916664"
136 height="0.26458672"
137 x="0.52916658"
138 y="296.73541" />
139 <rect
140 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071921;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
141 id="rect1509-6-9-6-8-2-2-76"
142 width="0.52916652"
143 height="0.26458672"
144 x="2.9104166"
145 y="294.08957" />
146 <rect
147 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071923;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
148 id="rect1509-6-9-6-8-2-2-73"
149 width="0.52916676"
150 height="0.26458672"
151 x="2.9104164"
152 y="295.41251" />
153 <rect
154 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.0707193;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
155 id="rect1509-6-9-6-8-2-2-7-5-6"
156 width="0.26458332"
157 height="0.52917457"
158 x="3.4395833"
159 y="294.61874" />
160 <rect
161 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.1000117;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
162 id="rect1509-6-9-9-3"
163 width="0.52916664"
164 height="0.52916938"
165 x="2.4494169e-09"
166 y="294.61874" />
167 <rect
168 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
169 id="rect1509-6-9-6-8-2-2-3-1-5-9"
170 width="0.26458332"
171 height="0.26458672"
172 x="5.5366083e-08"
173 y="294.35416" />
174 <rect
175 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
176 id="rect1509-6-9-6-8-2-2-3-1-5-4"
177 width="0.26458332"
178 height="0.26458672"
179 x="5.5366083e-08"
180 y="295.14792" />
181 <rect
182 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071895;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
183 id="rect1509-6-9-9-3-8"
184 width="0.26458332"
185 height="0.52916938"
186 x="3.9687495"
187 y="294.61874" />
188 <rect
189 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
190 id="rect1509-6-9-6-8-2-2-3-1-5-9-1"
191 width="0.26458332"
192 height="0.26458672"
193 x="3.9687498"
194 y="294.35416" />
195 <rect
196 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
197 id="rect1509-6-9-6-8-2-2-3-1-5-4-2"
198 width="0.26458332"
199 height="0.26458672"
200 x="3.9687498"
201 y="295.14792" />
202 <rect
203 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
204 id="rect1509-6-9-6-8-2-2-3-1-5-9-9"
205 width="0.26458332"
206 height="0.26458672"
89207 x="2.3812499"
90208 y="293.29584" />
91209 <rect
92 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.15813231;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
93 id="rect1509-6-9-3-1"
94 width="0.26458332"
95 height="2.6458435"
96 x="2.9104166"
97 y="293.56042" />
98 <rect
99 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001195;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
100 id="rect1509-6-9-3-6-0-8"
101 width="0.2645832"
102 height="1.0583434"
103 x="3.4395835"
104 y="294.35416"
105 inkscape:transform-center-x="0.81558898"
106 inkscape:transform-center-y="-1.6042942" />
107 <rect
108 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.1581316;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
109 id="rect1509-6-9-9"
110 width="0.26458332"
111 height="2.6458197"
112 x="0.26458332"
113 y="293.56042" />
114 <rect
115 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.10001113;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
116 id="rect1509-6-9-3-2"
117 width="0.26458326"
118 height="1.0583266"
119 x="0.79375005"
120 y="294.35416" />
121 <rect
122 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.18710472;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
123 id="rect1509-6-9-3-6-0-2"
124 width="0.26458329"
125 height="3.7041838"
126 x="1.3229167"
127 y="293.03125"
128 inkscape:transform-center-x="0.81558941"
129 inkscape:transform-center-y="-5.6149857" />
130 <rect
131 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.12248763;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
132 id="rect1509-6-9-3-6-0-8-9-4"
133 width="0.2645832"
134 height="1.587477"
210 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
211 id="rect1509-6-9-6-8-2-2-3-1-5-9-3"
212 width="0.26458332"
213 height="0.26458672"
214 x="2.3812499"
215 y="296.20624" />
216 <rect
217 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.15813197;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
218 id="rect1509-6-9-3-6-0-8-9-4-9"
219 width="0.26458305"
220 height="2.6458344"
221 x="2.3812499"
222 y="293.56042"
223 inkscape:transform-center-x="0.81559079"
224 inkscape:transform-center-y="-4.0106747" />
225 <rect
226 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.12248758;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
227 id="rect1509-6-9-3-6-0-2-0"
228 width="0.26458344"
229 height="1.5874749"
230 x="1.3229166"
231 y="294.0896"
232 inkscape:transform-center-x="0.81558972"
233 inkscape:transform-center-y="-2.4063427" />
234 <rect
235 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
236 id="rect1509-6-9-6-8-2-2-3-1-5-8"
237 width="0.26458332"
238 height="0.26458672"
239 x="1.3229166"
240 y="293.82501" />
241 <rect
242 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.05000604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
243 id="rect1509-6-9-6-8-2-2-3-1-5-85"
244 width="0.26458332"
245 height="0.26458672"
246 x="1.3229166"
247 y="295.67709" />
248 <rect
249 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071895;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
250 id="rect1509-6-9-9-3-0"
251 width="0.26458332"
252 height="0.52916938"
253 x="1.0583333"
254 y="294.61874" />
255 <rect
256 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071895;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
257 id="rect1509-6-9-9-3-0-9"
258 width="0.26458332"
259 height="0.52916938"
135260 x="1.8520832"
136 y="294.0896"
137 inkscape:transform-center-x="0.81558915"
138 inkscape:transform-center-y="-2.4063831" />
139 <rect
140 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071917;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
141 id="rect1509-6-9-3-1-3"
142 width="0.26458332"
143 height="0.5291723"
144 x="3.7041664"
145 y="294.61874" />
146 <rect
147 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071917;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
148 id="rect1509-6-9-3-1-3-6"
149 width="0.26458332"
150 height="0.5291723"
151 x="3.175"
152 y="294.61874" />
153 <rect
154 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071917;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
155 id="rect1509-6-9-3-1-3-6-7"
156 width="0.26458332"
157 height="0.5291723"
261 y="294.61874" />
262 <rect
263 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071895;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
264 id="rect1509-6-9-9-3-0-6"
265 width="0.26458332"
266 height="0.52916938"
158267 x="2.6458333"
159 y="294.61874" />
160 <rect
161 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071917;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
162 id="rect1509-6-9-3-1-3-6-5"
163 width="0.26458332"
164 height="0.5291723"
165 x="2.1166666"
166 y="294.61874" />
167 <rect
168 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071917;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
169 id="rect1509-6-9-3-1-3-6-5-3"
170 width="0.26458332"
171 height="0.5291723"
172 x="1.5875"
173 y="294.61874" />
174 <rect
175 style="opacity:0.5;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071917;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
176 id="rect1509-6-9-3-1-3-6-5-5"
177 width="0.26458332"
178 height="0.5291723"
179 x="1.0583333"
180 y="294.61874" />
181 <rect
182 style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:0.07071917;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
183 id="rect1509-6-9-3-1-3-6-5-6"
184 width="0.26458332"
185 height="0.5291723"
186 x="0.52916664"
187268 y="294.61874" />
188269 </g>
189270 </svg>
11 Type=Application
22 Name=Elektroid
33 Comment=Sample transfer application for Elektron devices
4 Comment[ca]=Aplicació de transferència de mostres per a dispositius Elektron
45 Comment[de]=Sample Transfer Anwendung für Elektron Instrumente
56 Comment[es]=Aplicación de transferencia de muestras para dispositivos Elektron
67 Comment[fr]=Application de transfert d'échantillon pour les périphériques Elektron
8 Comment[pt_BR]=Aplicativo de transferência de sample para dispositivos Elektron
79 Categories=Music;AudioVideo;X-Sound;Audio;X-Alsa
810 Keywords=music;alsa;realtime;standalone;
911 Exec=elektroid
00 <?xml version="1.0" encoding="UTF-8"?>
1 <!-- Generated with glade 3.22.1
1 <!-- Generated with glade 3.38.2
22
33 Copyright (C) David García Goñi
44
1919
2020 -->
2121 <interface>
22 <requires lib="gtk+" version="3.20"/>
22 <requires lib="gtk+" version="3.24"/>
23 <!-- interface-css-provider-path gui.css -->
2324 <!-- interface-license-type gplv3 -->
2425 <!-- interface-name Elektroid -->
2526 <!-- interface-description GNU/Linux sample transfer application for Elektron devices -->
3233 <column type="gchararray"/>
3334 </columns>
3435 </object>
36 <object class="GtkListStore" id="fs_list_store">
37 <columns>
38 <!-- column-name id -->
39 <column type="guint"/>
40 <!-- column-name icon -->
41 <column type="gchararray"/>
42 <!-- column-name name -->
43 <column type="gchararray"/>
44 </columns>
45 </object>
3546 <object class="GtkListStore" id="local_list_store">
3647 <columns>
37 <!-- column-name type -->
48 <!-- column-name icon -->
3849 <column type="gchararray"/>
3950 <!-- column-name name -->
4051 <column type="gchararray"/>
4152 <!-- column-name size -->
4253 <column type="gint"/>
43 <!-- column-name size_human -->
54 <!-- column-name size_str -->
4455 <column type="gchararray"/>
56 <!-- column-name type -->
57 <column type="gint"/>
58 <!-- column-name index -->
59 <column type="gint"/>
4560 </columns>
4661 </object>
4762 <object class="GtkMenu" id="local_menu">
4863 <property name="visible">True</property>
49 <property name="can_focus">False</property>
64 <property name="can-focus">False</property>
5065 <child>
5166 <object class="GtkMenuItem" id="upload_menuitem">
5267 <property name="visible">True</property>
53 <property name="can_focus">False</property>
68 <property name="can-focus">False</property>
5469 <property name="label" translatable="yes">Upload Selection</property>
55 <property name="use_underline">True</property>
70 <property name="use-underline">True</property>
5671 <accelerator key="Right" signal="activate" modifiers="GDK_CONTROL_MASK"/>
5772 </object>
5873 </child>
5974 <child>
6075 <object class="GtkSeparatorMenuItem">
6176 <property name="visible">True</property>
62 <property name="can_focus">False</property>
77 <property name="can-focus">False</property>
6378 </object>
6479 </child>
6580 <child>
6681 <object class="GtkMenuItem" id="local_play_menuitem">
6782 <property name="visible">True</property>
68 <property name="can_focus">False</property>
83 <property name="can-focus">False</property>
6984 <property name="label" translatable="yes">Play</property>
70 <property name="use_underline">True</property>
85 <property name="use-underline">True</property>
7186 </object>
7287 </child>
7388 <child>
7489 <object class="GtkSeparatorMenuItem">
7590 <property name="visible">True</property>
76 <property name="can_focus">False</property>
91 <property name="can-focus">False</property>
7792 </object>
7893 </child>
7994 <child>
8095 <object class="GtkMenuItem" id="local_open_menuitem">
8196 <property name="visible">True</property>
82 <property name="can_focus">False</property>
97 <property name="can-focus">False</property>
8398 <property name="label" translatable="yes">Open With External Editor</property>
84 <property name="use_underline">True</property>
99 <property name="use-underline">True</property>
85100 </object>
86101 </child>
87102 <child>
88103 <object class="GtkMenuItem" id="local_show_menuitem">
89104 <property name="visible">True</property>
90 <property name="can_focus">False</property>
105 <property name="can-focus">False</property>
91106 <property name="label" translatable="yes">Show in File Manager</property>
92 <property name="use_underline">True</property>
107 <property name="use-underline">True</property>
93108 </object>
94109 </child>
95110 <child>
96111 <object class="GtkSeparatorMenuItem">
97112 <property name="visible">True</property>
98 <property name="can_focus">False</property>
113 <property name="can-focus">False</property>
99114 </object>
100115 </child>
101116 <child>
102117 <object class="GtkMenuItem" id="local_rename_menuitem">
103118 <property name="visible">True</property>
104 <property name="can_focus">False</property>
119 <property name="can-focus">False</property>
105120 <property name="label" translatable="yes">Rename</property>
106 <property name="use_underline">True</property>
121 <property name="use-underline">True</property>
107122 <accelerator key="F2" signal="activate"/>
108123 </object>
109124 </child>
110125 <child>
111126 <object class="GtkMenuItem" id="local_delete_menuitem">
112127 <property name="visible">True</property>
113 <property name="can_focus">False</property>
128 <property name="can-focus">False</property>
114129 <property name="label" translatable="yes">Delete</property>
115 <property name="use_underline">True</property>
130 <property name="use-underline">True</property>
116131 <accelerator key="Delete" signal="activate"/>
117132 </object>
118133 </child>
119134 </object>
120135 <object class="GtkListStore" id="remote_list_store">
121136 <columns>
122 <!-- column-name type -->
137 <!-- column-name icon -->
123138 <column type="gchararray"/>
124139 <!-- column-name name -->
125140 <column type="gchararray"/>
126141 <!-- column-name size -->
127142 <column type="gint"/>
128 <!-- column-name human_size -->
143 <!-- column-name size_str -->
129144 <column type="gchararray"/>
145 <!-- column-name type -->
146 <column type="gint"/>
147 <!-- column-name index -->
148 <column type="gint"/>
130149 </columns>
131150 </object>
132151 <object class="GtkMenu" id="remote_menu">
133152 <property name="visible">True</property>
134 <property name="can_focus">False</property>
153 <property name="can-focus">False</property>
135154 <child>
136155 <object class="GtkMenuItem" id="download_menuitem">
137156 <property name="visible">True</property>
138 <property name="can_focus">False</property>
157 <property name="can-focus">False</property>
139158 <property name="label" translatable="yes">Download Selection</property>
140 <property name="use_underline">True</property>
159 <property name="use-underline">True</property>
141160 <accelerator key="Left" signal="activate" modifiers="GDK_CONTROL_MASK"/>
142161 </object>
143162 </child>
144163 <child>
145164 <object class="GtkSeparatorMenuItem">
146165 <property name="visible">True</property>
147 <property name="can_focus">False</property>
166 <property name="can-focus">False</property>
148167 </object>
149168 </child>
150169 <child>
151170 <object class="GtkMenuItem" id="remote_rename_menuitem">
152171 <property name="visible">True</property>
153 <property name="can_focus">False</property>
172 <property name="can-focus">False</property>
154173 <property name="label" translatable="yes">Rename</property>
155 <property name="use_underline">True</property>
174 <property name="use-underline">True</property>
156175 <accelerator key="F2" signal="activate"/>
157176 </object>
158177 </child>
159178 <child>
160179 <object class="GtkMenuItem" id="remote_delete_menuitem">
161180 <property name="visible">True</property>
162 <property name="can_focus">False</property>
181 <property name="can-focus">False</property>
163182 <property name="label" translatable="yes">Delete</property>
164 <property name="use_underline">True</property>
183 <property name="use-underline">True</property>
165184 <accelerator key="Delete" signal="activate"/>
166185 </object>
167186 </child>
182201 <column type="gchararray"/>
183202 <!-- column-name type_human -->
184203 <column type="gchararray"/>
204 <!-- column-name remote_fs_id -->
205 <column type="gint"/>
206 <!-- column-name remote_fs_icon -->
207 <column type="gchararray"/>
185208 </columns>
186209 </object>
187210 <object class="GtkAboutDialog" id="about_dialog">
188 <property name="can_focus">False</property>
211 <property name="can-focus">False</property>
189212 <property name="resizable">False</property>
190213 <property name="modal">True</property>
191 <property name="type_hint">dialog</property>
192 <property name="transient_for">main_window</property>
193 <property name="program_name">Elektroid</property>
214 <property name="type-hint">dialog</property>
215 <property name="transient-for">main_window</property>
216 <property name="program-name">Elektroid</property>
194217 <property name="copyright">Copyright © 2019 David García Goñi</property>
195 <property name="comments" translatable="yes">GNU/Linux sample transfer application for Elektron devices</property>
218 <property name="comments" translatable="yes">GNU/Linux transfer application for Elektron devices</property>
196219 <property name="website">https://github.com/dagargo/elektroid</property>
197220 <property name="authors">David García Goñi&lt;dagargo@gmail.com&gt;</property>
198 <property name="translator_credits" translatable="yes">translator-credits</property>
199 <property name="logo_icon_name">elektroid</property>
200 <property name="license_type">gpl-3-0</property>
201 <child>
202 <placeholder/>
203 </child>
221 <property name="translator-credits" translatable="yes">translator-credits</property>
222 <property name="logo-icon-name">elektroid</property>
223 <property name="license-type">gpl-3-0</property>
204224 <child internal-child="vbox">
205225 <object class="GtkBox">
206 <property name="can_focus">False</property>
226 <property name="can-focus">False</property>
207227 <property name="orientation">vertical</property>
208228 <property name="spacing">2</property>
209229 <child internal-child="action_area">
210230 <object class="GtkButtonBox">
211 <property name="can_focus">False</property>
212 <property name="layout_style">end</property>
231 <property name="can-focus">False</property>
232 <property name="layout-style">end</property>
213233 <child>
214234 <placeholder/>
215235 </child>
230250 </child>
231251 </object>
232252 <object class="GtkPopoverMenu" id="main_popover">
233 <property name="can_focus">False</property>
234 <property name="relative_to">menu_button</property>
253 <property name="can-focus">False</property>
254 <property name="relative-to">menu_button</property>
235255 <child>
236256 <object class="GtkBox">
237257 <property name="visible">True</property>
238 <property name="can_focus">False</property>
239 <property name="margin_left">9</property>
240 <property name="margin_right">9</property>
241 <property name="margin_top">9</property>
242 <property name="margin_bottom">9</property>
258 <property name="can-focus">False</property>
259 <property name="margin-left">9</property>
260 <property name="margin-right">9</property>
261 <property name="margin-top">9</property>
262 <property name="margin-bottom">9</property>
243263 <property name="orientation">vertical</property>
244264 <child>
245265 <object class="GtkModelButton" id="rx_sysex_button">
246266 <property name="visible">True</property>
247 <property name="can_focus">True</property>
248 <property name="receives_default">True</property>
267 <property name="can-focus">True</property>
268 <property name="receives-default">True</property>
249269 <property name="text" translatable="yes">_Receive SysEx</property>
250270 </object>
251271 <packing>
257277 <child>
258278 <object class="GtkModelButton" id="tx_sysex_button">
259279 <property name="visible">True</property>
260 <property name="can_focus">True</property>
261 <property name="receives_default">True</property>
280 <property name="can-focus">True</property>
281 <property name="receives-default">True</property>
262282 <property name="text" translatable="yes">_Send SysEx</property>
263283 </object>
264284 <packing>
270290 <child>
271291 <object class="GtkSeparator">
272292 <property name="visible">True</property>
273 <property name="can_focus">False</property>
293 <property name="can-focus">False</property>
274294 </object>
275295 <packing>
276296 <property name="expand">False</property>
281301 <child>
282302 <object class="GtkModelButton" id="os_upgrade_button">
283303 <property name="visible">True</property>
284 <property name="can_focus">True</property>
285 <property name="receives_default">True</property>
304 <property name="can-focus">True</property>
305 <property name="receives-default">True</property>
286306 <property name="text" translatable="yes">OS _Upgrade</property>
287307 </object>
288308 <packing>
294314 <child>
295315 <object class="GtkSeparator">
296316 <property name="visible">True</property>
297 <property name="can_focus">False</property>
317 <property name="can-focus">False</property>
298318 </object>
299319 <packing>
300320 <property name="expand">False</property>
305325 <child>
306326 <object class="GtkModelButton" id="about_button">
307327 <property name="visible">True</property>
308 <property name="can_focus">True</property>
309 <property name="receives_default">True</property>
328 <property name="can-focus">True</property>
329 <property name="receives-default">True</property>
310330 <property name="text" translatable="yes">_About</property>
311331 </object>
312332 <packing>
323343 </child>
324344 </object>
325345 <object class="GtkWindow" id="main_window">
326 <property name="can_focus">False</property>
327 <property name="icon_name">elektroid</property>
328 <child type="titlebar">
329 <object class="GtkHeaderBar">
330 <property name="visible">True</property>
331 <property name="can_focus">False</property>
332 <property name="title">Elektroid</property>
333 <property name="has_subtitle">False</property>
334 <property name="show_close_button">True</property>
335 <child>
336 <object class="GtkMenuButton" id="menu_button">
337 <property name="visible">True</property>
338 <property name="can_focus">True</property>
339 <property name="receives_default">True</property>
340 <property name="direction">none</property>
341 <property name="popover">main_popover</property>
342 <child>
343 <placeholder/>
344 </child>
345 </object>
346 <packing>
347 <property name="pack_type">end</property>
348 </packing>
349 </child>
350 </object>
351 </child>
346 <property name="can-focus">False</property>
347 <property name="icon-name">elektroid</property>
352348 <child>
353349 <object class="GtkBox">
354350 <property name="visible">True</property>
355 <property name="can_focus">False</property>
351 <property name="can-focus">False</property>
356352 <property name="orientation">vertical</property>
357353 <child>
358354 <object class="GtkPaned">
359355 <property name="visible">True</property>
360 <property name="can_focus">False</property>
361 <property name="margin_left">6</property>
362 <property name="margin_right">6</property>
363 <property name="margin_top">6</property>
356 <property name="can-focus">False</property>
357 <property name="margin-left">6</property>
358 <property name="margin-right">6</property>
359 <property name="margin-top">6</property>
364360 <property name="hexpand">True</property>
365361 <property name="vexpand">True</property>
366362 <property name="orientation">vertical</property>
367363 <child>
368364 <object class="GtkBox">
369365 <property name="visible">True</property>
370 <property name="can_focus">False</property>
371 <property name="margin_bottom">6</property>
366 <property name="can-focus">False</property>
367 <property name="margin-bottom">6</property>
372368 <property name="hexpand">True</property>
373369 <property name="vexpand">True</property>
374370 <property name="orientation">vertical</property>
375371 <property name="spacing">6</property>
376372 <child>
373 <!-- n-columns=2 n-rows=2 -->
377374 <object class="GtkGrid">
378375 <property name="visible">True</property>
379 <property name="can_focus">False</property>
376 <property name="can-focus">False</property>
380377 <property name="hexpand">True</property>
381378 <property name="vexpand">True</property>
382 <property name="row_spacing">6</property>
383 <property name="column_spacing">6</property>
379 <property name="row-spacing">6</property>
380 <property name="column-spacing">6</property>
384381 <child>
385382 <object class="GtkBox">
386383 <property name="visible">True</property>
387 <property name="can_focus">False</property>
384 <property name="can-focus">False</property>
388385 <property name="hexpand">True</property>
389386 <property name="vexpand">True</property>
390387 <property name="orientation">vertical</property>
392389 <child>
393390 <object class="GtkBox">
394391 <property name="visible">True</property>
395 <property name="can_focus">False</property>
392 <property name="can-focus">False</property>
396393 <property name="hexpand">True</property>
397394 <property name="spacing">6</property>
398395 <child>
399396 <object class="GtkEntry" id="local_dir_entry">
400397 <property name="visible">True</property>
401 <property name="can_focus">True</property>
398 <property name="can-focus">True</property>
402399 <property name="hexpand">True</property>
403400 <property name="editable">False</property>
404401 </object>
409406 </packing>
410407 </child>
411408 <child>
412 <object class="GtkBox">
413 <property name="visible">True</property>
414 <property name="can_focus">False</property>
415 <property name="halign">end</property>
416 <property name="spacing">6</property>
417 <child>
418 <object class="GtkButton" id="local_up_button">
419 <property name="name">local_up_button</property>
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">
420417 <property name="visible">True</property>
421 <property name="can_focus">True</property>
422 <property name="receives_default">True</property>
423 <property name="tooltip_text" translatable="yes">Go to Parent Directory</property>
424 <child>
425 <object class="GtkImage">
426 <property name="visible">True</property>
427 <property name="can_focus">False</property>
428 <property name="icon_name">go-up-symbolic</property>
429 </object>
430 </child>
431 </object>
432 <packing>
433 <property name="expand">False</property>
434 <property name="fill">True</property>
435 <property name="position">0</property>
436 </packing>
437 </child>
438 <child>
439 <object class="GtkButton" id="local_add_dir_button">
440 <property name="name">local_add_dir_button</property>
441 <property name="visible">True</property>
442 <property name="can_focus">True</property>
443 <property name="receives_default">True</property>
444 <property name="tooltip_text" translatable="yes">Add Directory</property>
445 <child>
446 <object class="GtkImage">
447 <property name="visible">True</property>
448 <property name="can_focus">False</property>
449 <property name="icon_name">folder-new-symbolic</property>
450 </object>
451 </child>
452 </object>
453 <packing>
454 <property name="expand">False</property>
455 <property name="fill">True</property>
456 <property name="position">1</property>
457 </packing>
458 </child>
459 <child>
460 <object class="GtkButton" id="local_refresh_button">
461 <property name="name">local_refresh_button</property>
462 <property name="visible">True</property>
463 <property name="can_focus">True</property>
464 <property name="receives_default">True</property>
465 <property name="tooltip_text" translatable="yes">Refresh Directory</property>
466 <child>
467 <object class="GtkImage">
468 <property name="visible">True</property>
469 <property name="can_focus">False</property>
470 <property name="icon_name">view-refresh-symbolic</property>
471 </object>
472 </child>
473 </object>
474 <packing>
475 <property name="expand">False</property>
476 <property name="fill">True</property>
477 <property name="position">2</property>
478 </packing>
418 <property name="can-focus">False</property>
419 <property name="icon-name">go-up-symbolic</property>
420 </object>
479421 </child>
480422 </object>
481423 <packing>
484426 <property name="position">1</property>
485427 </packing>
486428 </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>
487471 </object>
488472 <packing>
489473 <property name="expand">False</property>
493477 </child>
494478 <child>
495479 <object class="GtkScrolledWindow">
496 <property name="width_request">400</property>
497 <property name="height_request">200</property>
480 <property name="width-request">400</property>
481 <property name="height-request">200</property>
498482 <property name="visible">True</property>
499 <property name="can_focus">True</property>
483 <property name="can-focus">True</property>
500484 <property name="hexpand">True</property>
501485 <property name="vexpand">True</property>
502 <property name="shadow_type">in</property>
486 <property name="shadow-type">in</property>
503487 <child>
504488 <object class="GtkTreeView" id="local_tree_view">
505489 <property name="name">local_tree_view</property>
506490 <property name="visible">True</property>
507 <property name="can_focus">True</property>
491 <property name="can-focus">True</property>
508492 <property name="hexpand">True</property>
509493 <property name="vexpand">True</property>
510494 <property name="model">local_list_store</property>
511 <property name="search_column">1</property>
495 <property name="search-column">1</property>
512496 <child internal-child="selection">
513497 <object class="GtkTreeSelection">
514498 <property name="mode">multiple</property>
529513 <property name="title" translatable="yes">Name</property>
530514 <property name="expand">True</property>
531515 <child>
532 <object class="GtkCellRendererText" id="local_name_cell_renderer_text">
516 <object class="GtkCellRendererText">
533517 <property name="ellipsize">middle</property>
534518 </object>
535519 <attributes>
560544 </child>
561545 </object>
562546 <packing>
563 <property name="left_attach">0</property>
564 <property name="top_attach">1</property>
547 <property name="left-attach">0</property>
548 <property name="top-attach">1</property>
565549 </packing>
566550 </child>
567551 <child>
568552 <object class="GtkBox" id="remote_box">
569553 <property name="visible">True</property>
570 <property name="can_focus">False</property>
554 <property name="can-focus">False</property>
571555 <property name="hexpand">True</property>
572556 <property name="vexpand">True</property>
573557 <property name="orientation">vertical</property>
575559 <child>
576560 <object class="GtkBox">
577561 <property name="visible">True</property>
578 <property name="can_focus">False</property>
562 <property name="can-focus">False</property>
579563 <property name="hexpand">True</property>
580564 <property name="spacing">6</property>
581565 <child>
582566 <object class="GtkEntry" id="remote_dir_entry">
583567 <property name="visible">True</property>
584 <property name="can_focus">True</property>
568 <property name="can-focus">True</property>
585569 <property name="hexpand">True</property>
586570 <property name="editable">False</property>
587571 </object>
592576 </packing>
593577 </child>
594578 <child>
595 <object class="GtkBox">
596 <property name="visible">True</property>
597 <property name="can_focus">False</property>
598 <property name="halign">end</property>
599 <property name="spacing">6</property>
600 <child>
601 <object class="GtkButton" id="remote_up_button">
602 <property name="name">remote_up_button</property>
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">
603587 <property name="visible">True</property>
604 <property name="can_focus">True</property>
605 <property name="receives_default">True</property>
606 <property name="tooltip_text" translatable="yes">Go to Parent Directory</property>
607 <child>
608 <object class="GtkImage">
609 <property name="visible">True</property>
610 <property name="can_focus">False</property>
611 <property name="icon_name">go-up-symbolic</property>
612 </object>
613 </child>
614 </object>
615 <packing>
616 <property name="expand">False</property>
617 <property name="fill">True</property>
618 <property name="position">0</property>
619 </packing>
620 </child>
621 <child>
622 <object class="GtkButton" id="remote_add_dir_button">
623 <property name="name">remote_add_dir_button</property>
624 <property name="visible">True</property>
625 <property name="can_focus">True</property>
626 <property name="receives_default">True</property>
627 <property name="tooltip_text" translatable="yes">Add Directory</property>
628 <child>
629 <object class="GtkImage">
630 <property name="visible">True</property>
631 <property name="can_focus">False</property>
632 <property name="icon_name">folder-new-symbolic</property>
633 </object>
634 </child>
635 </object>
636 <packing>
637 <property name="expand">False</property>
638 <property name="fill">True</property>
639 <property name="position">1</property>
640 </packing>
641 </child>
642 <child>
643 <object class="GtkButton" id="remote_refresh_button">
644 <property name="name">remote_refresh_button</property>
645 <property name="visible">True</property>
646 <property name="can_focus">True</property>
647 <property name="receives_default">True</property>
648 <property name="tooltip_text" translatable="yes">Refresh Directory</property>
649 <child>
650 <object class="GtkImage">
651 <property name="visible">True</property>
652 <property name="can_focus">False</property>
653 <property name="icon_name">view-refresh-symbolic</property>
654 </object>
655 </child>
656 </object>
657 <packing>
658 <property name="expand">False</property>
659 <property name="fill">True</property>
660 <property name="position">2</property>
661 </packing>
588 <property name="can-focus">False</property>
589 <property name="icon-name">go-up-symbolic</property>
590 </object>
662591 </child>
663592 </object>
664593 <packing>
667596 <property name="position">1</property>
668597 </packing>
669598 </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>
670641 </object>
671642 <packing>
672643 <property name="expand">False</property>
676647 </child>
677648 <child>
678649 <object class="GtkScrolledWindow">
679 <property name="width_request">400</property>
680 <property name="height_request">200</property>
650 <property name="width-request">400</property>
651 <property name="height-request">200</property>
681652 <property name="visible">True</property>
682 <property name="can_focus">True</property>
653 <property name="can-focus">True</property>
683654 <property name="hexpand">True</property>
684655 <property name="vexpand">True</property>
685 <property name="shadow_type">in</property>
656 <property name="shadow-type">in</property>
686657 <child>
687658 <object class="GtkTreeView" id="remote_tree_view">
688659 <property name="name">remote_tree_view</property>
689660 <property name="visible">True</property>
690 <property name="can_focus">True</property>
661 <property name="can-focus">True</property>
691662 <property name="hexpand">True</property>
692663 <property name="vexpand">True</property>
693664 <property name="model">remote_list_store</property>
694 <property name="search_column">1</property>
665 <property name="search-column">1</property>
695666 <child internal-child="selection">
696667 <object class="GtkTreeSelection">
697668 <property name="mode">multiple</property>
703674 <object class="GtkCellRendererPixbuf"/>
704675 <attributes>
705676 <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>
706687 </attributes>
707688 </child>
708689 </object>
743724 </child>
744725 </object>
745726 <packing>
746 <property name="left_attach">1</property>
747 <property name="top_attach">1</property>
727 <property name="left-attach">1</property>
728 <property name="top-attach">1</property>
748729 </packing>
749730 </child>
750731 <child>
751732 <object class="GtkBox">
752733 <property name="visible">True</property>
753 <property name="can_focus">False</property>
734 <property name="can-focus">False</property>
754735 <property name="spacing">6</property>
755736 <child>
756737 <object class="GtkComboBox" id="devices_combo">
757738 <property name="visible">True</property>
758 <property name="can_focus">False</property>
739 <property name="can-focus">False</property>
759740 <property name="model">devices_list_store</property>
760741 <child>
761742 <object class="GtkCellRendererText"/>
774755 <object class="GtkButton" id="refresh_devices_button">
775756 <property name="name">refresh_devices_button</property>
776757 <property name="visible">True</property>
777 <property name="can_focus">True</property>
778 <property name="receives_default">True</property>
779 <property name="tooltip_text" translatable="yes">Refresh Devices</property>
758 <property name="can-focus">True</property>
759 <property name="receives-default">True</property>
760 <property name="tooltip-text" translatable="yes">Refresh Devices</property>
780761 <child>
781762 <object class="GtkImage">
782763 <property name="visible">True</property>
783 <property name="can_focus">False</property>
784 <property name="icon_name">view-refresh-symbolic</property>
764 <property name="can-focus">False</property>
765 <property name="icon-name">view-refresh-symbolic</property>
785766 </object>
786767 </child>
787768 </object>
791772 <property name="position">1</property>
792773 </packing>
793774 </child>
775 <child>
776 <object class="GtkSeparator">
777 <property name="visible">True</property>
778 <property name="can-focus">False</property>
779 </object>
780 <packing>
781 <property name="expand">False</property>
782 <property name="fill">True</property>
783 <property name="position">2</property>
784 </packing>
785 </child>
786 <child>
787 <object class="GtkComboBox" id="fs_combo">
788 <property name="visible">True</property>
789 <property name="can-focus">False</property>
790 <property name="model">fs_list_store</property>
791 <property name="entry-text-column">1</property>
792 <child>
793 <object class="GtkCellRendererPixbuf">
794 <property name="xpad">3</property>
795 </object>
796 <attributes>
797 <attribute name="icon-name">1</attribute>
798 </attributes>
799 </child>
800 <child>
801 <object class="GtkCellRendererText"/>
802 <attributes>
803 <attribute name="text">2</attribute>
804 </attributes>
805 </child>
806 </object>
807 <packing>
808 <property name="expand">False</property>
809 <property name="fill">True</property>
810 <property name="position">3</property>
811 </packing>
812 </child>
794813 </object>
795814 <packing>
796 <property name="left_attach">1</property>
797 <property name="top_attach">0</property>
815 <property name="left-attach">1</property>
816 <property name="top-attach">0</property>
798817 </packing>
799818 </child>
800819 <child>
801820 <object class="GtkLabel" id="hostname_label">
802821 <property name="visible">True</property>
803 <property name="can_focus">False</property>
822 <property name="can-focus">False</property>
804823 <property name="halign">start</property>
805824 <property name="hexpand">True</property>
806825 </object>
807826 <packing>
808 <property name="left_attach">0</property>
809 <property name="top_attach">0</property>
827 <property name="left-attach">0</property>
828 <property name="top-attach">0</property>
810829 </packing>
811830 </child>
812831 </object>
817836 </packing>
818837 </child>
819838 <child>
820 <object class="GtkBox">
839 <object class="GtkBox" id="local_audio_box">
821840 <property name="visible">True</property>
822 <property name="can_focus">False</property>
841 <property name="can-focus">False</property>
823842 <property name="hexpand">True</property>
824843 <property name="spacing">6</property>
825 <property name="baseline_position">bottom</property>
844 <property name="baseline-position">bottom</property>
826845 <child>
827846 <object class="GtkBox">
828847 <property name="visible">True</property>
829 <property name="can_focus">False</property>
848 <property name="can-focus">False</property>
830849 <property name="halign">start</property>
831850 <property name="valign">center</property>
832851 <property name="orientation">vertical</property>
834853 <child>
835854 <object class="GtkBox">
836855 <property name="visible">True</property>
837 <property name="can_focus">False</property>
856 <property name="can-focus">False</property>
838857 <property name="spacing">6</property>
839858 <child>
840859 <object class="GtkSwitch" id="autoplay_switch">
841860 <property name="name">autoplay_switch</property>
842861 <property name="visible">True</property>
843 <property name="can_focus">True</property>
862 <property name="can-focus">True</property>
844863 <property name="halign">start</property>
845864 <property name="valign">center</property>
846865 <property name="active">True</property>
854873 <child>
855874 <object class="GtkLabel">
856875 <property name="visible">True</property>
857 <property name="can_focus">False</property>
876 <property name="can-focus">False</property>
858877 <property name="valign">center</property>
859878 <property name="label" translatable="yes" comments="It is recommended to split the text in two lines if it is too long">Auto play</property>
860879 <property name="wrap">True</property>
875894 <child>
876895 <object class="GtkBox">
877896 <property name="visible">True</property>
878 <property name="can_focus">False</property>
897 <property name="can-focus">False</property>
879898 <property name="halign">center</property>
880899 <property name="spacing">6</property>
881900 <child>
882901 <object class="GtkBox">
883902 <property name="visible">True</property>
884 <property name="can_focus">False</property>
903 <property name="can-focus">False</property>
885904 <property name="halign">center</property>
886905 <child>
887906 <object class="GtkButton" id="play_button">
888907 <property name="name">play_button</property>
889908 <property name="visible">True</property>
890 <property name="can_focus">True</property>
891 <property name="receives_default">True</property>
909 <property name="can-focus">True</property>
910 <property name="receives-default">True</property>
892911 <property name="halign">center</property>
893912 <property name="valign">center</property>
894913 <child>
895914 <object class="GtkImage">
896915 <property name="visible">True</property>
897 <property name="can_focus">False</property>
898 <property name="icon_name">media-playback-start-symbolic</property>
916 <property name="can-focus">False</property>
917 <property name="icon-name">media-playback-start-symbolic</property>
899918 </object>
900919 </child>
901920 </object>
909928 <object class="GtkButton" id="stop_button">
910929 <property name="name">stop_button</property>
911930 <property name="visible">True</property>
912 <property name="can_focus">True</property>
913 <property name="receives_default">True</property>
931 <property name="can-focus">True</property>
932 <property name="receives-default">True</property>
914933 <property name="halign">center</property>
915934 <property name="valign">center</property>
916935 <child>
917936 <object class="GtkImage">
918937 <property name="visible">True</property>
919 <property name="can_focus">False</property>
920 <property name="icon_name">media-playback-stop-symbolic</property>
938 <property name="can-focus">False</property>
939 <property name="icon-name">media-playback-stop-symbolic</property>
921940 </object>
922941 </child>
923942 </object>
931950 <object class="GtkToggleButton" id="loop_button">
932951 <property name="name">loop_button</property>
933952 <property name="visible">True</property>
934 <property name="can_focus">True</property>
935 <property name="receives_default">True</property>
953 <property name="can-focus">True</property>
954 <property name="receives-default">True</property>
936955 <property name="valign">center</property>
937956 <child>
938957 <object class="GtkImage">
939958 <property name="visible">True</property>
940 <property name="can_focus">False</property>
941 <property name="icon_name">media-playlist-repeat-symbolic</property>
959 <property name="can-focus">False</property>
960 <property name="icon-name">media-playlist-repeat-symbolic</property>
942961 </object>
943962 </child>
944963 </object>
961980 <child>
962981 <object class="GtkVolumeButton" id="volume_button">
963982 <property name="visible">True</property>
964 <property name="can_focus">True</property>
965 <property name="focus_on_click">False</property>
966 <property name="receives_default">True</property>
983 <property name="can-focus">True</property>
984 <property name="focus-on-click">False</property>
985 <property name="receives-default">True</property>
967986 <property name="relief">none</property>
968987 <property name="orientation">vertical</property>
969988 <property name="icons">audio-volume-muted-symbolic
972991 audio-volume-medium-symbolic</property>
973992 <child internal-child="plus_button">
974993 <object class="GtkButton">
975 <property name="can_focus">True</property>
976 <property name="receives_default">True</property>
994 <property name="can-focus">True</property>
995 <property name="receives-default">True</property>
977996 <property name="halign">center</property>
978997 <property name="valign">center</property>
979998 <property name="relief">none</property>
9811000 </child>
9821001 <child internal-child="minus_button">
9831002 <object class="GtkButton">
984 <property name="can_focus">True</property>
985 <property name="receives_default">True</property>
1003 <property name="can-focus">True</property>
1004 <property name="receives-default">True</property>
9861005 <property name="halign">center</property>
9871006 <property name="valign">center</property>
9881007 <property name="relief">none</property>
10151034 <child>
10161035 <object class="GtkFrame">
10171036 <property name="visible">True</property>
1018 <property name="can_focus">False</property>
1037 <property name="can-focus">False</property>
10191038 <property name="hexpand">True</property>
1020 <property name="label_xalign">0</property>
1021 <property name="label_yalign">0</property>
1022 <property name="shadow_type">in</property>
1039 <property name="label-xalign">0</property>
1040 <property name="label-yalign">0</property>
1041 <property name="shadow-type">in</property>
10231042 <child>
10241043 <object class="GtkAlignment">
10251044 <property name="visible">True</property>
1026 <property name="can_focus">False</property>
1045 <property name="can-focus">False</property>
10271046 <child>
10281047 <object class="GtkDrawingArea" id="waveform_draw_area">
10291048 <property name="visible">True</property>
1030 <property name="can_focus">False</property>
1049 <property name="can-focus">False</property>
10311050 <property name="hexpand">True</property>
10321051 <style>
10331052 <class name="local"/>
10381057 </child>
10391058 <child type="label">
10401059 <object class="GtkLabel">
1041 <property name="can_focus">False</property>
1060 <property name="can-focus">False</property>
10421061 </object>
10431062 </child>
10441063 </object>
10641083 <child>
10651084 <object class="GtkBox">
10661085 <property name="visible">True</property>
1067 <property name="can_focus">False</property>
1068 <property name="margin_top">6</property>
1086 <property name="can-focus">False</property>
1087 <property name="margin-top">6</property>
10691088 <property name="hexpand">True</property>
10701089 <property name="spacing">6</property>
10711090 <child>
10721091 <object class="GtkScrolledWindow">
10731092 <property name="visible">True</property>
1074 <property name="can_focus">True</property>
1093 <property name="can-focus">True</property>
10751094 <property name="hexpand">True</property>
10761095 <property name="vexpand">True</property>
1077 <property name="shadow_type">in</property>
1096 <property name="shadow-type">in</property>
10781097 <child>
10791098 <object class="GtkTreeView" id="task_tree_view">
10801099 <property name="visible">True</property>
1081 <property name="can_focus">True</property>
1100 <property name="can-focus">True</property>
10821101 <property name="model">task_list_store</property>
1083 <property name="search_column">0</property>
1102 <property name="search-column">0</property>
10841103 <child internal-child="selection">
10851104 <object class="GtkTreeSelection">
10861105 <property name="mode">none</property>
11101129 </child>
11111130 <child>
11121131 <object class="GtkTreeViewColumn">
1132 <child>
1133 <object class="GtkCellRendererPixbuf"/>
1134 <attributes>
1135 <attribute name="icon-name">8</attribute>
1136 </attributes>
1137 </child>
1138 </object>
1139 </child>
1140 <child>
1141 <object class="GtkTreeViewColumn">
11131142 <property name="title" translatable="yes">Source</property>
11141143 <property name="expand">True</property>
11151144 <child>
11381167 </child>
11391168 <child>
11401169 <object class="GtkTreeViewColumn">
1141 <property name="fixed_width">120</property>
1170 <property name="fixed-width">120</property>
11421171 <property name="title" translatable="yes">Progress</property>
11431172 <child>
11441173 <object class="GtkCellRendererProgress"/>
11601189 <child>
11611190 <object class="GtkBox">
11621191 <property name="visible">True</property>
1163 <property name="can_focus">False</property>
1192 <property name="can-focus">False</property>
11641193 <property name="valign">start</property>
11651194 <property name="orientation">vertical</property>
11661195 <property name="spacing">6</property>
11691198 <object class="GtkButton" id="cancel_task_button">
11701199 <property name="visible">True</property>
11711200 <property name="sensitive">False</property>
1172 <property name="can_focus">True</property>
1173 <property name="receives_default">True</property>
1174 <property name="tooltip_text" translatable="yes">Cancel Tasks</property>
1201 <property name="can-focus">True</property>
1202 <property name="receives-default">True</property>
1203 <property name="tooltip-text" translatable="yes">Cancel Tasks</property>
11751204 <child>
11761205 <object class="GtkImage">
11771206 <property name="visible">True</property>
1178 <property name="can_focus">False</property>
1179 <property name="icon_name">edit-delete-symbolic</property>
1207 <property name="can-focus">False</property>
1208 <property name="icon-name">edit-delete-symbolic</property>
11801209 </object>
11811210 </child>
11821211 </object>
11901219 <object class="GtkButton" id="remove_tasks_button">
11911220 <property name="visible">True</property>
11921221 <property name="sensitive">False</property>
1193 <property name="can_focus">True</property>
1194 <property name="receives_default">True</property>
1195 <property name="tooltip_text" translatable="yes">Remove Queued Tasks</property>
1222 <property name="can-focus">True</property>
1223 <property name="receives-default">True</property>
1224 <property name="tooltip-text" translatable="yes">Remove Queued Tasks</property>
11961225 <child>
11971226 <object class="GtkImage">
11981227 <property name="visible">True</property>
1199 <property name="can_focus">False</property>
1200 <property name="icon_name">list-remove-all-symbolic</property>
1228 <property name="can-focus">False</property>
1229 <property name="icon-name">list-remove-all-symbolic</property>
12011230 </object>
12021231 </child>
12031232 </object>
12111240 <object class="GtkButton" id="clear_tasks_button">
12121241 <property name="visible">True</property>
12131242 <property name="sensitive">False</property>
1214 <property name="can_focus">True</property>
1215 <property name="receives_default">True</property>
1216 <property name="tooltip_text" translatable="yes">Clear Finished Tasks</property>
1243 <property name="can-focus">True</property>
1244 <property name="receives-default">True</property>
1245 <property name="tooltip-text" translatable="yes">Clear Finished Tasks</property>
12171246 <child>
12181247 <object class="GtkImage">
12191248 <property name="visible">True</property>
1220 <property name="can_focus">False</property>
1221 <property name="icon_name">edit-clear-all-symbolic</property>
1249 <property name="can-focus">False</property>
1250 <property name="icon-name">edit-clear-all-symbolic</property>
12221251 </object>
12231252 </child>
12241253 </object>
12511280 <child>
12521281 <object class="GtkStatusbar" id="status_bar">
12531282 <property name="visible">True</property>
1254 <property name="can_focus">False</property>
1283 <property name="can-focus">False</property>
12551284 <property name="orientation">vertical</property>
12561285 </object>
12571286 <packing>
12621291 </child>
12631292 </object>
12641293 </child>
1294 <child type="titlebar">
1295 <object class="GtkHeaderBar">
1296 <property name="visible">True</property>
1297 <property name="can-focus">False</property>
1298 <property name="title">Elektroid</property>
1299 <property name="show-close-button">True</property>
1300 <child>
1301 <object class="GtkMenuButton" id="menu_button">
1302 <property name="visible">True</property>
1303 <property name="can-focus">True</property>
1304 <property name="receives-default">True</property>
1305 <property name="direction">none</property>
1306 <property name="popover">main_popover</property>
1307 <child>
1308 <placeholder/>
1309 </child>
1310 </object>
1311 <packing>
1312 <property name="pack-type">end</property>
1313 </packing>
1314 </child>
1315 </object>
1316 </child>
12651317 </object>
12661318 <object class="GtkDialog" id="name_dialog">
1267 <property name="can_focus">False</property>
1319 <property name="can-focus">False</property>
12681320 <property name="resizable">False</property>
12691321 <property name="modal">True</property>
1270 <property name="type_hint">dialog</property>
1271 <property name="transient_for">main_window</property>
1272 <child>
1273 <placeholder/>
1274 </child>
1322 <property name="type-hint">dialog</property>
1323 <property name="transient-for">main_window</property>
12751324 <child internal-child="vbox">
12761325 <object class="GtkBox">
1277 <property name="can_focus">False</property>
1278 <property name="margin_left">6</property>
1279 <property name="margin_right">6</property>
1280 <property name="margin_top">6</property>
1281 <property name="margin_bottom">6</property>
1326 <property name="can-focus">False</property>
1327 <property name="margin-left">6</property>
1328 <property name="margin-right">6</property>
1329 <property name="margin-top">6</property>
1330 <property name="margin-bottom">6</property>
12821331 <property name="orientation">vertical</property>
12831332 <property name="spacing">6</property>
12841333 <child internal-child="action_area">
12851334 <object class="GtkButtonBox">
1286 <property name="can_focus">False</property>
1287 <property name="layout_style">end</property>
1335 <property name="can-focus">False</property>
1336 <property name="layout-style">end</property>
12881337 <child>
12891338 <object class="GtkButton" id="name_dialog_cancel_button">
12901339 <property name="label">gtk-cancel</property>
12911340 <property name="visible">True</property>
1292 <property name="can_focus">True</property>
1293 <property name="receives_default">True</property>
1294 <property name="use_stock">True</property>
1341 <property name="can-focus">True</property>
1342 <property name="receives-default">True</property>
1343 <property name="use-stock">True</property>
12951344 </object>
12961345 <packing>
12971346 <property name="expand">False</property>
13031352 <object class="GtkButton" id="name_dialog_accept_button">
13041353 <property name="label">gtk-ok</property>
13051354 <property name="visible">True</property>
1306 <property name="can_focus">True</property>
1307 <property name="can_default">True</property>
1308 <property name="has_default">True</property>
1309 <property name="receives_default">False</property>
1310 <property name="use_stock">True</property>
1355 <property name="can-focus">True</property>
1356 <property name="can-default">True</property>
1357 <property name="has-default">True</property>
1358 <property name="receives-default">False</property>
1359 <property name="use-stock">True</property>
13111360 </object>
13121361 <packing>
13131362 <property name="expand">False</property>
13251374 <child>
13261375 <object class="GtkBox">
13271376 <property name="visible">True</property>
1328 <property name="can_focus">False</property>
1329 <property name="margin_bottom">6</property>
1377 <property name="can-focus">False</property>
1378 <property name="margin-bottom">6</property>
13301379 <property name="spacing">6</property>
13311380 <child>
13321381 <object class="GtkLabel">
13331382 <property name="visible">True</property>
1334 <property name="can_focus">False</property>
1383 <property name="can-focus">False</property>
13351384 <property name="label" translatable="yes">Name</property>
13361385 </object>
13371386 <packing>
13431392 <child>
13441393 <object class="GtkEntry" id="name_dialog_entry">
13451394 <property name="visible">True</property>
1346 <property name="can_focus">True</property>
1347 <property name="is_focus">True</property>
1395 <property name="can-focus">True</property>
1396 <property name="is-focus">True</property>
13481397 <property name="hexpand">True</property>
1349 <property name="max_length">32</property>
1350 <property name="activates_default">True</property>
1351 <property name="input_purpose">alpha</property>
1398 <property name="max-length">32</property>
1399 <property name="activates-default">True</property>
1400 <property name="input-purpose">alpha</property>
13521401 </object>
13531402 <packing>
13541403 <property name="expand">False</property>
13671416 </child>
13681417 </object>
13691418 <object class="GtkDialog" id="progress_dialog">
1370 <property name="can_focus">False</property>
1419 <property name="can-focus">False</property>
13711420 <property name="resizable">False</property>
13721421 <property name="modal">True</property>
1373 <property name="type_hint">dialog</property>
1374 <property name="transient_for">main_window</property>
1375 <child>
1376 <placeholder/>
1377 </child>
1422 <property name="type-hint">dialog</property>
1423 <property name="transient-for">main_window</property>
13781424 <child internal-child="vbox">
13791425 <object class="GtkBox">
1380 <property name="can_focus">False</property>
1381 <property name="margin_left">6</property>
1382 <property name="margin_right">6</property>
1383 <property name="margin_top">6</property>
1384 <property name="margin_bottom">6</property>
1426 <property name="can-focus">False</property>
1427 <property name="margin-left">6</property>
1428 <property name="margin-right">6</property>
1429 <property name="margin-top">6</property>
1430 <property name="margin-bottom">6</property>
13851431 <property name="orientation">vertical</property>
13861432 <property name="spacing">6</property>
13871433 <child internal-child="action_area">
13881434 <object class="GtkButtonBox">
1389 <property name="can_focus">False</property>
1390 <property name="layout_style">end</property>
1435 <property name="can-focus">False</property>
1436 <property name="layout-style">end</property>
13911437 <child>
13921438 <object class="GtkButton" id="progress_dialog_cancel_button">
13931439 <property name="label">gtk-cancel</property>
13941440 <property name="visible">True</property>
1395 <property name="can_focus">True</property>
1396 <property name="receives_default">True</property>
1397 <property name="use_stock">True</property>
1441 <property name="can-focus">True</property>
1442 <property name="receives-default">True</property>
1443 <property name="use-stock">True</property>
13981444 </object>
13991445 <packing>
14001446 <property name="expand">True</property>
14121458 <child>
14131459 <object class="GtkBox">
14141460 <property name="visible">True</property>
1415 <property name="can_focus">False</property>
1416 <property name="margin_bottom">6</property>
1461 <property name="can-focus">False</property>
1462 <property name="margin-bottom">6</property>
14171463 <property name="orientation">vertical</property>
14181464 <property name="spacing">6</property>
14191465 <child>
14201466 <object class="GtkLabel" id="progress_label">
14211467 <property name="visible">True</property>
1422 <property name="can_focus">False</property>
1468 <property name="can-focus">False</property>
14231469 <property name="halign">start</property>
14241470 </object>
14251471 <packing>
14311477 <child>
14321478 <object class="GtkProgressBar" id="progress_bar">
14331479 <property name="visible">True</property>
1434 <property name="can_focus">False</property>
1480 <property name="can-focus">False</property>
14351481 </object>
14361482 <packing>
14371483 <property name="expand">False</property>
00 PKG_CONFIG ?= pkg-config
11
2 AM_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags alsa gtk+-3.0 libpulse libpulse-mainloop-glib zlib` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS)
3 elektroid_LDFLAGS = `$(PKG_CONFIG) --libs alsa gtk+-3.0 libpulse libpulse-mainloop-glib zlib` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS)
4 elektroid_cli_LDFLAGS = `$(PKG_CONFIG) --libs alsa glib-2.0 zlib` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS)
2 GUI_LIBS = alsa gtk+-3.0 libpulse libpulse-mainloop-glib zlib json-glib-1.0 libzip
3 CLI_LIBS = alsa glib-2.0 zlib json-glib-1.0 libzip
54
5 elektroid_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(GUI_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS)
6 elektroid_LDFLAGS = `$(PKG_CONFIG) --libs $(GUI_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS)
7 elektroid_cli_CFLAGS = -I$(top_srcdir)/src `$(PKG_CONFIG) --cflags $(CLI_LIBS)` $(SNDFILE_CFLAGS) $(SAMPLERATE_CFLAGS)
8 elektroid_cli_LDFLAGS = `$(PKG_CONFIG) --libs $(CLI_LIBS)` $(SNDFILE_LIBS) $(SAMPLERATE_LIBS)
9
10 if CLI_ONLY
11 bin_PROGRAMS = elektroid-cli
12 else
613 bin_PROGRAMS = elektroid elektroid-cli
7 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
8 elektroid_cli_SOURCES = connector.c connector.h elektroid-cli.c sample.c sample.h utils.c utils.h
14 endif
15
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
918
1019 SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
1120 SNDFILE_LIBS = @SNDFILE_LIBS@
1919
2020 #include "../config.h"
2121 #include "audio.h"
22 #include "utils.h"
2322
2423 #define PA_BUFFER_LEN 4800
2524 #define CHANNELS 1
4645 gshort *v;
4746 gint i;
4847
49 //XXX: Until a better solution is found this corks the stream without using neither drain nor empty buffers (CPU)
5048 if (audio->release_frames > PA_BUFFER_LEN)
5149 {
52 audio_stop (audio, FALSE);
53 return;
54 }
55
56 req_frames = size / 2;
50 pa_stream_cork (audio->stream, 1, NULL, NULL);
51 return;
52 }
53
54 req_frames = size >> 1;
5755 debug_print (2, "Writing %2d frames...\n", req_frames);
5856 pa_stream_begin_write (stream, &buffer, &size);
5957
60 g_mutex_lock (&audio->mutex);
58 g_mutex_lock (&audio->control.mutex);
6159
6260 if (!audio->sample->len)
6361 {
64 g_mutex_unlock (&audio->mutex);
62 g_mutex_unlock (&audio->control.mutex);
6563 pa_stream_cancel_write (stream);
6664 debug_print (2, "Canceled\n");
6765 return;
6866 }
6967
70 if (audio->pos == audio->sample->len && !audio->loop)
71 {
72 g_mutex_unlock (&audio->mutex);
68 if (audio->pos == audio->sample->len >> 1 && !audio->loop)
69 {
70 g_mutex_unlock (&audio->control.mutex);
7371 memset (buffer, 0, size);
7472 pa_stream_write (stream, buffer, size, NULL, 0, PA_SEEK_RELATIVE);
7573 audio->release_frames += req_frames;
7977 v = buffer;
8078 for (i = 0; i < req_frames; i++)
8179 {
82 if (audio->pos < audio->sample->len)
80 if (audio->pos < audio->sample->len >> 1)
8381 {
8482 *v = ((short *) audio->sample->data)[audio->pos];
8583 audio->pos++;
9997 v++;
10098 }
10199
102 g_mutex_unlock (&audio->mutex);
100 g_mutex_unlock (&audio->control.mutex);
103101
104102 pa_stream_write (stream, buffer, i * 2, NULL, 0, PA_SEEK_RELATIVE);
105103 }
116114
117115 debug_print (1, "Stopping audio...\n");
118116
117 pa_threaded_mainloop_lock (audio->mainloop);
119118 if (flush)
120119 {
121120 operation = pa_stream_flush (audio->stream, NULL, NULL);
130129 {
131130 pa_operation_unref (operation);
132131 }
132 pa_threaded_mainloop_unlock (audio->mainloop);
133133 }
134134
135135 void
146146
147147 debug_print (1, "Playing audio...\n");
148148
149 g_mutex_lock (&audio->mutex);
149 g_mutex_lock (&audio->control.mutex);
150150 audio->pos = 0;
151151 audio->release_frames = 0;
152 g_mutex_unlock (&audio->mutex);
153
152 g_mutex_unlock (&audio->control.mutex);
153
154 pa_threaded_mainloop_lock (audio->mainloop);
154155 operation = pa_stream_cork (audio->stream, 0, NULL, NULL);
155156 if (operation != NULL)
156157 {
157158 pa_operation_unref (operation);
158159 }
160 pa_threaded_mainloop_unlock (audio->mainloop);
159161 }
160162
161163 static void
167169 if (info && pa_cvolume_valid (&info->volume))
168170 {
169171 gdouble v = pa_sw_volume_to_linear (pa_cvolume_avg (&info->volume));
170 audio->set_volume_gui_callback (v);
172 audio->volume_change_callback (v);
171173 }
172174 }
173175
246248 }
247249
248250 gint
249 audio_init (struct audio *audio, void (*set_volume_gui_callback) (gdouble))
251 audio_init (struct audio *audio, void (*volume_change_callback) (gdouble),
252 void (*load_progress_callback) (gdouble))
250253 {
251254 pa_mainloop_api *api;
252255 gint err = 0;
253256
254257 debug_print (1, "Initializing audio...\n");
255258
256 audio->sample = g_array_new (FALSE, FALSE, sizeof (gshort));
259 audio->sample = g_byte_array_new ();
260 audio->frames = 0;
257261 audio->loop = FALSE;
258 audio->mainloop = pa_glib_mainloop_new (NULL);
259 api = pa_glib_mainloop_get_api (audio->mainloop);
262 audio->mainloop = pa_threaded_mainloop_new ();
263 api = pa_threaded_mainloop_get_api (audio->mainloop);
260264 audio->context = pa_context_new (api, PACKAGE);
261265 audio->stream = NULL;
262266 audio->index = PA_INVALID_INDEX;
263 audio->set_volume_gui_callback = set_volume_gui_callback;
267 audio->volume_change_callback = volume_change_callback;
268 audio->control.callback = load_progress_callback;
269 audio->name = malloc (PATH_MAX);
270 audio->name[0] = 0;
264271
265272 if (pa_context_connect (audio->context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
266273 {
267274 pa_context_unref (audio->context);
268 pa_glib_mainloop_free (audio->mainloop);
275 pa_threaded_mainloop_free (audio->mainloop);
269276 audio->mainloop = NULL;
270277 err = -1;
271278 }
273280 {
274281 pa_context_set_state_callback (audio->context, audio_context_callback,
275282 audio);
283 pa_threaded_mainloop_start (audio->mainloop);
284
285
276286 }
277287
278288 return err;
284294 debug_print (1, "Destroying audio...\n");
285295
286296 audio_stop (audio, TRUE);
287 g_array_free (audio->sample, TRUE);
297
298 g_byte_array_free (audio->sample, TRUE);
288299 if (audio->stream)
289300 {
290301 pa_stream_unref (audio->stream);
294305 if (audio->mainloop)
295306 {
296307 pa_context_unref (audio->context);
297 pa_glib_mainloop_free (audio->mainloop);
308 pa_threaded_mainloop_stop (audio->mainloop);
309 pa_threaded_mainloop_free (audio->mainloop);
298310 audio->mainloop = NULL;
299311 }
312
313 g_free (audio->name);
300314 }
301315
302316 gboolean
308322 void
309323 audio_reset_sample (struct audio *audio)
310324 {
311 g_mutex_lock (&audio->mutex);
312 g_array_set_size (audio->sample, 0);
325 g_mutex_lock (&audio->control.mutex);
326 g_byte_array_set_size (audio->sample, 0);
327 audio->frames = 0;
313328 audio->pos = 0;
314 g_mutex_unlock (&audio->mutex);
329 g_mutex_unlock (&audio->control.mutex);
315330 }
316331
317332 void
1919
2020 #include <glib.h>
2121 #include <pulse/pulseaudio.h>
22 #include <pulse/glib-mainloop.h>
22 #include "utils.h"
2323
2424 struct audio
2525 {
26 GArray *sample;
27 gint frames;
26 GByteArray *sample;
27 guint frames;
2828 gboolean loop;
29 pa_glib_mainloop *mainloop;
29 pa_threaded_mainloop *mainloop;
3030 pa_context *context;
3131 pa_stream *stream;
3232 gint pos;
3333 pa_cvolume volume;
3434 uint32_t index;
35 void (*set_volume_gui_callback) (gdouble);
35 void (*volume_change_callback) (gdouble);
3636 gint release_frames;
37 GMutex mutex;
38 gboolean load_active;
37 struct job_control control;
38 gchar *name;
3939 };
4040
4141 void audio_play (struct audio *);
4444
4545 gboolean audio_check (struct audio *);
4646
47 gint audio_init (struct audio *, void (*)(gdouble));
47 gint audio_init (struct audio *, void (*)(gdouble), void (*)(gdouble));
4848
4949 void audio_destroy (struct audio *);
5050
1818 */
1919
2020 #include "browser.h"
21 #include "utils.h"
2221
2322 gint
24 browser_sort (GtkTreeModel * model,
25 GtkTreeIter * a, GtkTreeIter * b, gpointer data)
26 {
23 browser_sort_samples (GtkTreeModel * model,
24 GtkTreeIter * a, GtkTreeIter * b, gpointer data)
25 {
26 struct item *itema;
27 struct item *itemb;
2728 gint ret = 0;
28 gchar *type1, *type2;
29 gchar *name1, *name2;
30
31 gtk_tree_model_get (model, a, 0, &type1, -1);
32 gtk_tree_model_get (model, b, 0, &type2, -1);
33
34 if (type1 == NULL || type2 == NULL)
35 {
36 if (type1 == NULL && type2 == NULL)
37 {
38 ret = 0;
39 }
40 else
41 {
42 if (type1 == NULL)
43 {
44 ret = -1;
45 g_free (type2);
46 }
47 else
48 {
49 ret = 1;
50 g_free (type1);
51 }
52 }
29
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);
5336 }
5437 else
5538 {
56 ret = -g_utf8_collate (type1, type2);
57 g_free (type1);
58 g_free (type2);
59 if (ret == 0)
60 {
61 gtk_tree_model_get (model, a, 1, &name1, -1);
62 gtk_tree_model_get (model, b, 1, &name2, -1);
63 if (name1 == NULL || name2 == NULL)
64 {
65 if (name1 == NULL && name2 == NULL)
66 {
67 ret = 0;
68 }
69 else
70 {
71 if (name1 == NULL)
72 {
73 ret = -1;
74 g_free (name2);
75 }
76 else
77 {
78 ret = 1;
79 g_free (name1);
80 }
81 }
82 }
83 else
84 {
85 ret = g_utf8_collate (name1, name2);
86 g_free (name1);
87 g_free (name2);
88 }
89 }
90 }
39 ret = itema->type > itemb->type;
40 }
41
42 browser_free_item (itema);
43 browser_free_item (itemb);
9144
9245 return ret;
9346 }
9447
95 void
96 browser_get_item_info (GtkTreeModel * model, GtkTreeIter * iter,
97 gchar ** type, gchar ** name, gint * size)
98 {
99 if (type)
100 {
101 gtk_tree_model_get (model, iter, BROWSER_LIST_STORE_ICON_TYPE_FIELD,
102 type, -1);
103 }
104 if (name)
105 {
106 gtk_tree_model_get (model, iter, BROWSER_LIST_STORE_NAME_FIELD, name,
107 -1);
108 }
109 if (size)
110 {
111 gtk_tree_model_get (model, iter, BROWSER_LIST_STORE_SIZE_FIELD, size,
112 -1);
113 }
48 gint
49 browser_sort_data (GtkTreeModel * model,
50 GtkTreeIter * a, GtkTreeIter * b, gpointer data)
51 {
52 struct item *itema;
53 struct item *itemb;
54 gint ret = 0;
55
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);
63
64 return ret;
65 }
66
67 struct item *
68 browser_get_item (GtkTreeModel * model, GtkTreeIter * iter)
69 {
70 struct item *item = malloc (sizeof (struct item));
71
72 gtk_tree_model_get (model, iter, BROWSER_LIST_STORE_TYPE_FIELD, &item->type,
73 BROWSER_LIST_STORE_NAME_FIELD, &item->name,
74 BROWSER_LIST_STORE_SIZE_FIELD, &item->size,
75 BROWSER_LIST_STORE_INDEX_FIELD, &item->index, -1);
76
77 return item;
11478 }
11579
11680 void
149113 browser_refresh (GtkWidget * object, gpointer data)
150114 {
151115 struct browser *browser = data;
152 g_idle_add (browser->load_dir, NULL);
116 g_idle_add (browser_load_dir, browser);
153117 }
154118
155119 void
165129 new_path = dirname (dup);
166130 strcpy (browser->dir, new_path);
167131 free (dup);
168 }
169
170 g_idle_add (browser->load_dir, NULL);
132 if (browser->notify_dir_change)
133 {
134 browser->notify_dir_change (browser);
135 }
136 }
137
138 g_idle_add (browser_load_dir, browser);
171139 }
172140
173141 void
174142 browser_item_activated (GtkTreeView * view, GtkTreePath * path,
175143 GtkTreeViewColumn * column, gpointer data)
176144 {
177 gchar *icon;
178 gchar *name;
179145 GtkTreeIter iter;
146 struct item *item;
180147 struct browser *browser = data;
181148 GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model
182149 (browser->view));
183150
184151 gtk_tree_model_get_iter (model, &iter, path);
185 browser_get_item_info (model, &iter, &icon, &name, NULL);
186
187 if (get_type_from_inventory_icon (icon) == ELEKTROID_DIR)
152 item = browser_get_item (model, &iter);
153
154 if (item->type == ELEKTROID_DIR)
188155 {
189156 if (strcmp (browser->dir, "/") != 0)
190157 {
191158 strcat (browser->dir, "/");
192159 }
193 strcat (browser->dir, name);
194 browser->load_dir (NULL);
195 }
196
197 g_free (icon);
198 g_free (name);
160 strcat (browser->dir, item->name);
161 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);
199169 }
200170
201171 gint
205175 gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view));
206176 return gtk_tree_selection_count_selected_rows (selection);
207177 }
178
179 void
180 browser_free_item (struct item *item)
181 {
182 g_free (item->name);
183 g_free (item);
184 }
185
186 gchar *
187 browser_get_item_path (struct browser *browser, struct item *item)
188 {
189 gchar *path = chain_path (browser->dir, item->name);
190 debug_print (1, "Using %s path for item %s (%d)...\n", path, item->name,
191 item->index);
192 return path;
193 }
194
195 gchar *
196 browser_get_item_id_path (struct browser *browser, struct item *item)
197 {
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);
203 return path;
204 }
205
206 static void
207 local_add_dentry_item (struct browser *browser, struct item_iterator *iter)
208 {
209 gchar *hsize;
210 GtkListStore *list_store =
211 GTK_LIST_STORE (gtk_tree_view_get_model (browser->view));
212
213 hsize = iter->item.size ? get_human_size (iter->item.size, TRUE) : "";
214
215 gtk_list_store_insert_with_values (list_store, NULL, -1,
216 BROWSER_LIST_STORE_ICON_FIELD,
217 iter->item.type ==
218 ELEKTROID_DIR ? DIR_ICON :
219 browser->file_icon,
220 BROWSER_LIST_STORE_NAME_FIELD,
221 iter->item.name,
222 BROWSER_LIST_STORE_SIZE_FIELD,
223 iter->item.size,
224 BROWSER_LIST_STORE_SIZE_STR_FIELD,
225 hsize,
226 BROWSER_LIST_STORE_TYPE_FIELD,
227 iter->item.type,
228 BROWSER_LIST_STORE_INDEX_FIELD,
229 iter->item.index, -1);
230 if (strlen (hsize))
231 {
232 g_free (hsize);
233 }
234 }
235
236 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;
269 }
270
271 gboolean
272 browser_load_dir (gpointer data)
273 {
274 struct item_iterator iter;
275 struct browser *browser = data;
276
277 browser_reset (browser);
278
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);
300 return FALSE;
301 }
1919
2020 #include <gtk/gtk.h>
2121 #include <libgen.h>
22 #include "utils.h"
2223
23 #define BROWSER_LIST_STORE_ICON_TYPE_FIELD 0
24 #define BROWSER_LIST_STORE_NAME_FIELD 1
25 #define BROWSER_LIST_STORE_SIZE_FIELD 2
26 #define BROWSER_LIST_STORE_HUMAN_SIZE_FIELD 3
24 #ifndef BROWSER_H
25 #define BROWSER_H
26
27 #define SIZE_LABEL_LEN 16
28
29 #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"
34
35 enum browser_list_field
36 {
37 BROWSER_LIST_STORE_ICON_FIELD = 0,
38 BROWSER_LIST_STORE_NAME_FIELD,
39 BROWSER_LIST_STORE_SIZE_FIELD,
40 BROWSER_LIST_STORE_SIZE_STR_FIELD,
41 BROWSER_LIST_STORE_TYPE_FIELD,
42 BROWSER_LIST_STORE_INDEX_FIELD
43 };
2744
2845 struct browser
2946 {
30 gint (*mkdir) (const gchar *);
31 gint (*rename) (const gchar *, const gchar *);
32 gint (*delete) (const gchar *, const gchar);
33 GSourceFunc load_dir;
3447 GSourceFunc check_selection;
3548 GtkTreeView *view;
3649 GtkWidget *up_button;
4356 GtkTreePath *dnd_motion_path;
4457 gint dnd_timeout_function_id;
4558 GString *dnd_data;
59 void (*notify_dir_change) (struct browser *);
60 const gchar *file_icon;
61 gchar **extensions;
62 const struct fs_operations *fs_ops;
63 void *data;
64 gboolean (*check_callback) ();
4665 };
4766
48 gint browser_sort (GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, gpointer);
67 gint browser_sort_samples (GtkTreeModel *, GtkTreeIter *, GtkTreeIter *,
68 gpointer);
4969
50 void browser_get_item_info (GtkTreeModel *, GtkTreeIter *, gchar **, gchar **,
51 gint *);
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 *);
5276
5377 gint browser_get_selected_items_count (struct browser *);
5478
6488
6589 void browser_item_activated (GtkTreeView *, GtkTreePath *,
6690 GtkTreeViewColumn *, gpointer);
91
92 gchar *browser_get_item_path (struct browser *, struct item *);
93
94 gchar *browser_get_item_id_path (struct browser *, struct item *);
95
96 gboolean browser_load_dir (gpointer);
97
98 #endif
2020 #include <stdio.h>
2121 #include <math.h>
2222 #include <endian.h>
23 #include <sys/poll.h>
23 #include <poll.h>
2424 #include <zlib.h>
2525 #include <libgen.h>
26 #include <json-glib/json-glib.h>
2627 #include "connector.h"
2728 #include "utils.h"
29 #include "sample.h"
30 #include "package.h"
2831
2932 #define KB 1024
3033 #define BUFF_SIZE (4 * KB)
3134 #define RING_BUFF_SIZE (256 * KB)
32 #define TRANSF_BLOCK_SIZE_SAMPLE 0x2000
33 #define TRANSF_BLOCK_SIZE_OS 0x800
35 #define DATA_TRANSF_BLOCK_BYTES 0x2000
36 #define OS_TRANSF_BLOCK_BYTES 0x800
3437 #define POLL_TIMEOUT 20
35 #define REST_TIME 50000
38 #define MAX_ZIP_SIZE (128 * 1024 * 1024)
39
40 #define AFMK1_ID 0x04
41 #define AKEYS_ID 0x06
42 #define ARMK1_ID 0x08
43 #define AHMK1_ID 0x0a
44 #define DTAKT_ID 0x0c
45 #define AFMK2_ID 0x0e
46 #define ARMK2_ID 0x10
47 #define DTONE_ID 0x14
48 #define AHMK2_ID 0x16
49 #define DKEYS_ID 0x1c
50 #define MOD_S_ID 0x19
51 #define MOD_C_ID 0x1b
52
53 #define FS_DATA_PRJ_PREFIX "/projects"
54 #define FS_DATA_SND_PREFIX "/soundbanks"
55 #define FS_SAMPLES_START_POS 5
56 #define FS_DATA_START_POS 18
57 #define FS_SAMPLES_SIZE_POS_W 21
58 #define FS_SAMPLES_LAST_FRAME_POS_W 33
59 #define FS_SAMPLES_PAD_RES 22
60 #define ELEKTRON_SAMPLE_INFO_PAD_I32_LEN 10
61
62 struct elektron_sample_info
63 {
64 guint32 type;
65 guint32 sample_len_bytes;
66 guint32 sample_rate;
67 guint32 loop_start;
68 guint32 loop_end;
69 guint32 loop_type;
70 guint32 padding[ELEKTRON_SAMPLE_INFO_PAD_I32_LEN];
71 };
72
73 typedef GByteArray *(*connector_msg_id_func) (guint);
74
75 typedef GByteArray *(*connector_msg_id_len_func) (guint, guint);
76
77 typedef GByteArray *(*connector_msg_path_func) (const gchar *);
78
79 typedef GByteArray *(*connector_msg_path_len_func) (const gchar *, guint);
80
81 typedef GByteArray *(*connector_msg_read_blk_func) (guint, guint, guint);
82
83 typedef GByteArray *(*connector_msg_write_blk_func) (guint, GByteArray *,
84 guint *, guint, void *);
85
86 typedef void (*connector_copy_array) (GByteArray *, GByteArray *);
87
88 typedef gint (*connector_path_func) (struct connector *, const gchar *);
89
90 typedef gint (*connector_src_dst_func) (struct connector *, const gchar *,
91 const gchar *);
92
93 static gint connector_delete_samples_dir (struct connector *, const gchar *);
94
95 static gint connector_read_samples_dir (struct item_iterator *, const gchar *,
96 void *);
97
98 static gint connector_create_samples_dir (const gchar *, void *);
99
100 static gint connector_delete_samples_item (const gchar *, void *);
101
102 static gint connector_move_samples_item (const gchar *, const gchar *,
103 void *);
104
105 static gint connector_download_sample (const gchar *, GByteArray *,
106 struct job_control *, void *);
107
108 static gint connector_upload_sample (const gchar *, GByteArray *,
109 struct job_control *, void *);
110
111 static gint connector_delete_raw_dir (struct connector *, const gchar *);
112
113 static gint connector_read_raw_dir (struct item_iterator *, const gchar *,
114 void *);
115
116 static gint connector_create_raw_dir (const gchar *, void *);
117
118 static gint connector_delete_raw_item (const gchar *, void *);
119
120 static gint connector_move_raw_item (const gchar *, const gchar *, void *);
121
122 static gint connector_download_raw (const gchar *, GByteArray *,
123 struct job_control *, void *);
124
125 static gint connector_upload_raw (const gchar *, GByteArray *,
126 struct job_control *, void *);
127
128 static gint connector_read_data_dir_any (struct item_iterator *,
129 const gchar *, void *);
130
131 static gint connector_read_data_dir_prj (struct item_iterator *,
132 const gchar *, void *);
133
134 static gint connector_read_data_dir_snd (struct item_iterator *,
135 const gchar *, void *);
136
137 static gint connector_move_data_item_any (const gchar *, const gchar *,
138 void *);
139 static gint connector_move_data_item_prj (const gchar *, const gchar *,
140 void *);
141 static gint connector_move_data_item_snd (const gchar *, const gchar *,
142 void *);
143
144 static gint connector_copy_data_item_any (const gchar *, const gchar *,
145 void *);
146
147 static gint connector_copy_data_item_prj (const gchar *, const gchar *,
148 void *);
149
150 static gint connector_copy_data_item_snd (const gchar *, const gchar *,
151 void *);
152
153 static gint connector_clear_data_item_any (const gchar *, void *);
154
155 static gint connector_clear_data_item_prj (const gchar *, void *);
156
157 static gint connector_clear_data_item_snd (const gchar *, void *);
158
159 static gint connector_swap_data_item_any (const gchar *, const gchar *,
160 void *);
161
162 static gint connector_swap_data_item_prj (const gchar *, const gchar *,
163 void *);
164
165 static gint connector_swap_data_item_snd (const gchar *, const gchar *,
166 void *);
167
168 static gint connector_download_data_any (const gchar *, GByteArray *,
169 struct job_control *, void *);
170
171 static gint connector_download_data_snd_pkg (const gchar *, GByteArray *,
172 struct job_control *, void *);
173
174 static gint connector_download_data_prj_pkg (const gchar *, GByteArray *,
175 struct job_control *, void *);
176
177 static gint connector_download_raw_pst_pkg (const gchar *, GByteArray *,
178 struct job_control *, void *);
179
180
181 static gint connector_upload_data_any (const gchar *, GByteArray *,
182 struct job_control *, void *);
183
184 static gint connector_upload_data_prj_pkg (const gchar *, GByteArray *,
185 struct job_control *, void *);
186
187 static gint connector_upload_data_snd_pkg (const gchar *, GByteArray *,
188 struct job_control *, void *);
189
190 static gint connector_upload_raw_pst_pkg (const gchar *, GByteArray *,
191 struct job_control *, void *);
192
193 static gint connector_copy_iterator (struct item_iterator *,
194 struct item_iterator *, gboolean);
36195
37196 static const guint8 MSG_HEADER[] = { 0xf0, 0, 0x20, 0x3c, 0x10, 0 };
38197
39 static const guint8 INQ_DEVICE[] = { 0x1 };
40 static const guint8 INQ_VERSION[] = { 0x2 };
41 static const guint8 INQ_UID[] = { 0x3 };
42 static const guint8 INQ_STORAGE_INFO[] = { 0x5 };
43 static const guint8 INQ_LS_DIR_TEMPLATE[] = { 0x10 };
44 static const guint8 INQ_NEW_DIR_TEMPLATE[] = { 0x11 };
45 static const guint8 INQ_DELETE_DIR_TEMPLATE[] = { 0x12 };
46 static const guint8 INQ_DELETE_FILE_TEMPLATE[] = { 0x20 };
47 static const guint8 INQ_RENAME_TEMPLATE[] = { 0x21 };
48 static const guint8 INQ_OPEN_FILE_READ_TEMPLATE[] = { 0x30 };
49 static const guint8 INQ_FILE_READ_BLK_TEMPLATE[] =
198 static const guint8 PING_REQUEST[] = { 0x1 };
199 static const guint8 SOFTWARE_VERSION_REQUEST[] = { 0x2 };
200 static const guint8 DEVICEUID_REQUEST[] = { 0x3 };
201 static const guint8 STORAGEINFO_REQUEST[] = { 0x5 };
202
203 static const guint8 FS_SAMPLE_READ_DIR_REQUEST[] = { 0x10 };
204 static const guint8 FS_SAMPLE_CREATE_DIR_REQUEST[] = { 0x11 };
205 static const guint8 FS_SAMPLE_DELETE_DIR_REQUEST[] = { 0x12 };
206 static const guint8 FS_SAMPLE_DELETE_FILE_REQUEST[] = { 0x20 };
207 static const guint8 FS_SAMPLE_RENAME_FILE_REQUEST[] = { 0x21 };
208 static const guint8 FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST[] =
209 { 0x23, 0, 0, 0, 0, 0, 0, 0, 0 };
210 static const guint8 FS_SAMPLE_OPEN_FILE_READER_REQUEST[] = { 0x30 };
211 static const guint8 FS_SAMPLE_CLOSE_FILE_READER_REQUEST[] = { 0x31 };
212 static const guint8 FS_SAMPLE_READ_FILE_REQUEST[] =
50213 { 0x32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
51 static const guint8 INQ_CLOSE_FILE_READ_TEMPLATE[] = { 0x31 };
52 static const guint8 INQ_OPEN_FILE_WRITE_TEMPLATE[] = { 0x40, 0, 0, 0, 0 };
53
54 static const guint8 INQ_FILE_WRITE_BLK_TEMPLATE_1ST[] =
55 { 0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 0, 0, 0, 0, 0, 0, 0, 0xbb, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0x7f,
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0
214 static const guint8 FS_SAMPLE_OPEN_FILE_WRITER_REQUEST[] =
215 { 0x40, 0, 0, 0, 0 };
216 static const guint8 FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST[] =
217 { 0x41, 0, 0, 0, 0, 0, 0, 0, 0 };
218 static const guint8 FS_SAMPLE_WRITE_FILE_REQUEST[] =
219 { 0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
220
221 static const guint8 FS_RAW_READ_DIR_REQUEST[] = { 0x14 };
222 static const guint8 FS_RAW_CREATE_DIR_REQUEST[] = { 0x15 };
223 static const guint8 FS_RAW_DELETE_DIR_REQUEST[] = { 0x16 };
224 static const guint8 FS_RAW_DELETE_FILE_REQUEST[] = { 0x24 };
225 static const guint8 FS_RAW_RENAME_FILE_REQUEST[] = { 0x25 };
226 static const guint8 FS_RAW_OPEN_FILE_READER_REQUEST[] = { 0x33 };
227 static const guint8 FS_RAW_CLOSE_FILE_READER_REQUEST[] = { 0x34 };
228 static const guint8 FS_RAW_READ_FILE_REQUEST[] =
229 { 0x35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
230 static const guint8 FS_RAW_OPEN_FILE_WRITER_REQUEST[] = { 0x43, 0, 0, 0, 0 };
231 static const guint8 FS_RAW_CLOSE_FILE_WRITER_REQUEST[] =
232 { 0x44, 0, 0, 0, 0, 0, 0, 0, 0 };
233 static const guint8 FS_RAW_WRITE_FILE_REQUEST[] =
234 { 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
235
236 static const guint8 DATA_LIST_REQUEST[] = { 0x53 };
237 static const guint8 DATA_READ_OPEN_REQUEST[] = { 0x54 };
238 static const guint8 DATA_READ_PARTIAL_REQUEST[] = { 0x55 };
239 static const guint8 DATA_READ_CLOSE_REQUEST[] = { 0x56 };
240 static const guint8 DATA_WRITE_OPEN_REQUEST[] = { 0x57 };
241 static const guint8 DATA_WRITE_PARTIAL_REQUEST[] = { 0x58 };
242 static const guint8 DATA_WRITE_CLOSE_REQUEST[] = { 0x59 };
243 static const guint8 DATA_MOVE_REQUEST[] = { 0x5a };
244 static const guint8 DATA_COPY_REQUEST[] = { 0x5b };
245 static const guint8 DATA_CLEAR_REQUEST[] = { 0x5c };
246 static const guint8 DATA_SWAP_REQUEST[] = { 0x5d };
247 static const guint8 OS_UPGRADE_START_REQUEST[] =
248 { 0x50, 0, 0, 0, 0, 's', 'y', 's', 'e', 'x', '\0', 1 };
249 static const guint8 OS_UPGRADE_WRITE_RESPONSE[] =
250 { 0x51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
251
252 static const gchar *FS_TYPE_NAMES[] = { "+Drive", "RAM" };
253
254 static const struct connector_device_desc ANALOG_FOUR_DESC = {
255 .name = "Analog Four",
256 .alias = "af",
257 .id = AFMK1_ID,
258 .fss = FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
259 .storages = 0
60260 };
61 static const guint8 INQ_FILE_WRITE_BLK_TEMPLATE_NTH[] =
62 { 0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
63 static const guint8 INQ_CLOSE_FILE_WRITE_TEMPLATE[] =
64 { 0x41, 0, 0, 0, 0, 0, 0, 0, 0 };
65
66 static const guint8 INQ_OS_UPGRADE_START[] =
67 { 0x50, 0, 0, 0, 0, 's', 'y', 's', 'e', 'x', '\0', 1 };
68 static const guint8 INQ_OS_UPGRADE_WRITE[] =
69 { 0x51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
70
71
72 static const gchar *FS_TYPE_NAMES[] = { "None", "+Drive", "RAM" };
261
262 static const struct connector_device_desc ANALOG_KEYS_DESC = {
263 .name = "Analog Keys",
264 .alias = "ak",
265 .id = AKEYS_ID,
266 .fss = FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
267 .storages = 0
268 };
73269
74270 static const struct connector_device_desc ANALOG_RYTM_DESC = {
75 .id = 0x8,
76 .model = "Analog Rytm",
77 .capabilities = CAP_SAMPLE,
78 .startup_mode = CAP_SAMPLE
271 .name = "Analog Rytm",
272 .alias = "ar",
273 .id = ARMK1_ID,
274 .fss = FS_SAMPLES | FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
275 .storages = STORAGE_PLUS_DRIVE | STORAGE_RAM
79276 };
80277
278 static const struct connector_device_desc ANALOG_HEAT_DESC = {
279 .name = "Analog Heat",
280 .alias = "ah",
281 .id = AHMK1_ID,
282 .fss = FS_DATA_ALL | FS_DATA_SND,
283 .storages = 0
284 };
285
81286 static const struct connector_device_desc DIGITAKT_DESC = {
82 .id = 0xc,
83 .model = "Digitakt",
84 .capabilities = CAP_SAMPLE,
85 .startup_mode = CAP_SAMPLE
287 .name = "Digitakt",
288 .alias = "dt",
289 .id = DTAKT_ID,
290 .fss = FS_SAMPLES | FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
291 .storages = STORAGE_PLUS_DRIVE | STORAGE_RAM
86292 };
87293
294 static const struct connector_device_desc ANALOG_FOUR_MKII_DESC = {
295 .name = "Analog Four MKII",
296 .alias = "af",
297 .id = AFMK2_ID,
298 .fss = FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
299 .storages = 0
300 };
301
88302 static const struct connector_device_desc ANALOG_RYTM_MKII_DESC = {
89 .id = 0x10,
90 .model = "Analog Rytm MKII",
91 .capabilities = CAP_SAMPLE,
92 .startup_mode = CAP_SAMPLE,
303 .name = "Analog Rytm MKII",
304 .alias = "ar",
305 .id = ARMK2_ID,
306 .fss = FS_SAMPLES | FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
307 .storages = STORAGE_PLUS_DRIVE | STORAGE_RAM
93308 };
94309
310 static const struct connector_device_desc DIGITONE_DESC = {
311 .name = "Digitone",
312 .alias = "dn",
313 .id = DTONE_ID,
314 .fss = FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
315 .storages = 0
316 };
317
318 static const struct connector_device_desc ANALOG_HEAT_MKII_DESC = {
319 .name = "Analog Heat MKII",
320 .alias = "ah",
321 .id = AHMK2_ID,
322 .fss = FS_DATA_ALL | FS_DATA_SND,
323 .storages = 0
324 };
325
326 static const struct connector_device_desc DIGITONE_KEYS_DESC = {
327 .name = "Digitone Keys",
328 .alias = "dn",
329 .id = DKEYS_ID,
330 .fss = FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
331 .storages = 0
332 };
333
95334 static const struct connector_device_desc MODEL_SAMPLES_DESC = {
96 .id = 0x19,
97 .model = "Model:Samples",
98 .capabilities = CAP_SAMPLE,
99 .startup_mode = CAP_SAMPLE
335 .name = "Model:Samples",
336 .alias = "ms",
337 .id = MOD_S_ID,
338 .fss = FS_SAMPLES | FS_DATA_ALL | FS_DATA_PRJ | FS_DATA_SND,
339 .storages = STORAGE_PLUS_DRIVE | STORAGE_RAM
100340 };
101341
102 static const struct connector_device_desc NULL_DEVICE_DESC = {
103 .id = 0,
104 .model = "-",
105 .capabilities = 0,
106 .startup_mode = 0
342 static const struct connector_device_desc MODEL_CYCLES_DESC = {
343 .name = "Model:Cycles",
344 .alias = "mc",
345 .id = MOD_C_ID,
346 .fss = FS_RAW_ALL | FS_RAW_PRESETS | FS_DATA_ALL | FS_DATA_PRJ,
347 .storages = STORAGE_PLUS_DRIVE
107348 };
108349
109350 static const struct connector_device_desc *CONNECTOR_DEVICE_DESCS[] = {
110 &ANALOG_RYTM_DESC, &DIGITAKT_DESC, &ANALOG_RYTM_MKII_DESC,
111 &MODEL_SAMPLES_DESC
351 &ANALOG_FOUR_DESC, &ANALOG_KEYS_DESC, &ANALOG_RYTM_DESC, &ANALOG_HEAT_DESC,
352 &DIGITAKT_DESC, &ANALOG_FOUR_MKII_DESC, &ANALOG_RYTM_MKII_DESC,
353 &DIGITONE_DESC, &ANALOG_HEAT_MKII_DESC, &DIGITONE_KEYS_DESC,
354 &MODEL_SAMPLES_DESC, &MODEL_CYCLES_DESC
112355 };
113356
114 static gchar connector_get_path_type (struct connector *, const gchar *);
115 static guchar
357 static const struct fs_operations FS_SAMPLES_OPERATIONS = {
358 .fs = FS_SAMPLES,
359 .readdir = connector_read_samples_dir,
360 .mkdir = connector_create_samples_dir,
361 .delete = connector_delete_samples_item,
362 .rename = connector_move_samples_item,
363 .move = connector_move_samples_item,
364 .copy = NULL,
365 .clear = NULL,
366 .swap = NULL,
367 .download = connector_download_sample,
368 .upload = connector_upload_sample,
369 .getid = get_item_name,
370 .load = sample_load,
371 .save = sample_save,
372 .extension = "wav"
373 };
374
375 static const struct fs_operations FS_RAW_ANY_OPERATIONS = {
376 .fs = FS_RAW_ALL,
377 .readdir = connector_read_raw_dir,
378 .mkdir = connector_create_raw_dir,
379 .delete = connector_delete_raw_item,
380 .rename = connector_move_raw_item,
381 .move = connector_move_raw_item,
382 .copy = NULL,
383 .clear = NULL,
384 .swap = NULL,
385 .download = connector_download_raw,
386 .upload = connector_upload_raw,
387 .getid = get_item_name,
388 .load = load_file,
389 .save = save_file,
390 .extension = "raw"
391 };
392
393 static const struct fs_operations FS_RAW_PRESETS_OPERATIONS = {
394 .fs = FS_RAW_PRESETS,
395 .readdir = connector_read_raw_dir,
396 .mkdir = connector_create_raw_dir,
397 .delete = connector_delete_raw_item,
398 .rename = connector_move_raw_item,
399 .move = connector_move_raw_item,
400 .copy = NULL,
401 .clear = NULL,
402 .swap = NULL,
403 .download = connector_download_raw_pst_pkg,
404 .upload = connector_upload_raw_pst_pkg,
405 .getid = get_item_name,
406 .load = load_file,
407 .save = save_file,
408 .extension = "pst"
409 };
410
411 static const struct fs_operations FS_DATA_ANY_OPERATIONS = {
412 .fs = FS_DATA_ALL,
413 .readdir = connector_read_data_dir_any,
414 .mkdir = NULL,
415 .delete = connector_clear_data_item_any,
416 .rename = NULL,
417 .move = connector_move_data_item_any,
418 .copy = connector_copy_data_item_any,
419 .clear = connector_clear_data_item_any,
420 .swap = connector_swap_data_item_any,
421 .download = connector_download_data_any,
422 .upload = connector_upload_data_any,
423 .getid = get_item_index,
424 .load = load_file,
425 .save = save_file,
426 .extension = "data"
427 };
428
429 static const struct fs_operations FS_DATA_PRJ_OPERATIONS = {
430 .fs = FS_DATA_PRJ,
431 .readdir = connector_read_data_dir_prj,
432 .mkdir = NULL,
433 .delete = connector_clear_data_item_prj,
434 .rename = NULL,
435 .move = connector_move_data_item_prj,
436 .copy = connector_copy_data_item_prj,
437 .clear = connector_clear_data_item_prj,
438 .swap = connector_swap_data_item_prj,
439 .download = connector_download_data_prj_pkg,
440 .upload = connector_upload_data_prj_pkg,
441 .getid = get_item_index,
442 .load = load_file,
443 .save = save_file,
444 .extension = "prj"
445 };
446
447 static const struct fs_operations FS_DATA_SND_OPERATIONS = {
448 .fs = FS_DATA_SND,
449 .readdir = connector_read_data_dir_snd,
450 .mkdir = NULL,
451 .delete = connector_clear_data_item_snd,
452 .rename = NULL,
453 .move = connector_move_data_item_snd,
454 .copy = connector_copy_data_item_snd,
455 .clear = connector_clear_data_item_snd,
456 .swap = connector_swap_data_item_snd,
457 .download = connector_download_data_snd_pkg,
458 .upload = connector_upload_data_snd_pkg,
459 .getid = get_item_index,
460 .load = load_file,
461 .save = save_file,
462 .extension = "snd"
463 };
464
465 static const struct fs_operations *FS_OPERATIONS[] = {
466 &FS_SAMPLES_OPERATIONS, &FS_RAW_ANY_OPERATIONS, &FS_RAW_PRESETS_OPERATIONS,
467 &FS_DATA_ANY_OPERATIONS, &FS_DATA_PRJ_OPERATIONS, &FS_DATA_SND_OPERATIONS
468 };
469
470 static const int FS_OPERATIONS_N =
471 sizeof (FS_OPERATIONS) / sizeof (struct fs_operations *);
472
473 static enum item_type connector_get_path_type (struct connector *,
474 const gchar *,
475 fs_init_iter_func);
476
477 static void
478 connector_free_iterator_data (void *iter_data)
479 {
480 struct connector_iterator_data *data = iter_data;
481
482 if (!data->cached)
483 {
484 free_msg (data->msg);
485 }
486 g_free (data);
487 }
488
489 const struct fs_operations *
490 connector_get_fs_operations (enum connector_fs fs)
491 {
492 const struct fs_operations *fs_operations = NULL;
493 for (int i = 0; i < FS_OPERATIONS_N; i++)
494 {
495 if (FS_OPERATIONS[i]->fs == fs)
496 {
497 fs_operations = FS_OPERATIONS[i];
498 break;
499 }
500 }
501 return fs_operations;
502 }
503
504 static inline gchar *
505 connector_get_utf8 (const gchar * s)
506 {
507 return g_convert (s, -1, "UTF8", "CP1252", NULL, NULL, NULL);
508 }
509
510 static inline gchar *
511 connector_get_cp1252 (const gchar * s)
512 {
513 return g_convert (s, -1, "CP1252", "UTF8", NULL, NULL, NULL);
514 }
515
516 static inline guint8
116517 connector_get_msg_status (const GByteArray * msg)
117518 {
118519 return msg->data[5];
119520 }
120521
121 static gchar *
522 static inline gchar *
122523 connector_get_msg_string (const GByteArray * msg)
123524 {
124525 return (gchar *) & msg->data[6];
125526 }
126527
127 void
128 free_msg (gpointer msg)
129 {
130 g_byte_array_free ((GByteArray *) msg, TRUE);
131 }
132
133 void
134 connector_free_dir_iterator (struct connector_dir_iterator *d_iter)
135 {
136 free_msg (d_iter->msg);
137 free (d_iter);
138 }
139
140 struct connector_dir_iterator *
141 connector_new_dir_iterator (GByteArray * msg)
142 {
143 struct connector_dir_iterator *dir_iterator =
144 malloc (sizeof (struct connector_dir_iterator));
145
146 dir_iterator->dentry = NULL;
147 dir_iterator->msg = msg;
148 dir_iterator->pos = 5;
149
150 return dir_iterator;
151 }
152
153 guint
154 connector_get_next_dentry (struct connector_dir_iterator *dir_iterator)
155 {
156 uint32_t *data;
157 gchar *dentry_cp1252;
158
159 if (dir_iterator->dentry != NULL)
160 {
161 g_free (dir_iterator->dentry);
162 }
163
164 if (dir_iterator->pos == dir_iterator->msg->len)
165 {
166 dir_iterator->dentry = NULL;
528 static guint
529 connector_next_smplrw_entry (struct item_iterator *iter)
530 {
531 guint32 *data32;
532 gchar *name_cp1252;
533 struct connector_iterator_data *data = iter->data;
534
535 if (iter->item.name != NULL)
536 {
537 g_free (iter->item.name);
538 }
539
540 if (data->pos == data->msg->len)
541 {
542 iter->item.name = NULL;
167543 return -ENOENT;
168544 }
169545 else
170546 {
171 data = (uint32_t *) & dir_iterator->msg->data[dir_iterator->pos];
172 dir_iterator->cksum = be32toh (*data);
173
174 dir_iterator->pos += 4;
175 data = (uint32_t *) & dir_iterator->msg->data[dir_iterator->pos];
176 dir_iterator->size = be32toh (*data);
177
178 dir_iterator->pos += 5;
179 dir_iterator->type = dir_iterator->msg->data[dir_iterator->pos];
180
181 dir_iterator->pos++;
182 dentry_cp1252 = (gchar *) & dir_iterator->msg->data[dir_iterator->pos];
183 dir_iterator->dentry =
184 g_convert (dentry_cp1252, -1, "UTF8", "CP1252", NULL, NULL, NULL);
185
186 while (dir_iterator->pos < dir_iterator->msg->len
187 && dir_iterator->msg->data[dir_iterator->pos] != 0)
188 {
189
190 dir_iterator->pos++;
191 }
192
193 dir_iterator->pos++;
547 data32 = (guint32 *) & data->msg->data[data->pos];
548 data->hash = be32toh (*data32);
549 data->pos += sizeof (guint32);
550
551 data32 = (guint32 *) & data->msg->data[data->pos];
552 iter->item.size = be32toh (*data32);
553 data->pos += sizeof (guint32);
554
555 data->pos++; //write_protected
556
557 iter->item.type = data->msg->data[data->pos];
558 data->pos++;
559
560 name_cp1252 = (gchar *) & data->msg->data[data->pos];
561 iter->item.name = connector_get_utf8 (name_cp1252);
562 if (data->fs == FS_RAW_ALL && iter->item.type == ELEKTROID_FILE)
563 {
564 //This eliminates the extension ".mc-snd" that the device provides.
565 iter->item.name[strlen (iter->item.name) - 7] = 0;
566 }
567 data->pos += strlen (name_cp1252) + 1;
568
569 iter->item.index = -1;
194570
195571 return 0;
196572 }
573 }
574
575 static gint
576 connector_init_iterator (struct item_iterator *iter, GByteArray * msg,
577 iterator_next next, enum connector_fs fs,
578 gboolean cached)
579 {
580 struct connector_iterator_data *data =
581 malloc (sizeof (struct connector_iterator_data));
582
583 data->msg = msg;
584 data->pos = fs == FS_DATA_ALL ? FS_DATA_START_POS : FS_SAMPLES_START_POS;
585 data->fs = fs;
586 data->cached = cached;
587
588 iter->data = data;
589 iter->next = next;
590 iter->free = connector_free_iterator_data;
591 iter->copy = connector_copy_iterator;
592 iter->item.name = NULL;
593 iter->item.index = -1;
594
595 return 0;
596 }
597
598 static gint
599 connector_copy_iterator (struct item_iterator *dst, struct item_iterator *src,
600 gboolean cached)
601 {
602 GByteArray *array;
603 struct connector_iterator_data *data = src->data;
604 if (cached)
605 {
606 array = data->msg;
607 }
608 else
609 {
610 array = g_byte_array_sized_new (data->msg->len);
611 g_byte_array_append (array, data->msg->data, data->msg->len);
612 }
613 return connector_init_iterator (dst, array, src->next, data->fs, cached);
197614 }
198615
199616 static GByteArray *
254671 }
255672
256673 static GByteArray *
257 connector_msg_to_sysex (const GByteArray * msg)
674 connector_msg_to_raw (const GByteArray * msg)
258675 {
259676 GByteArray *encoded;
260677 GByteArray *sysex = g_byte_array_new ();
268685 return sysex;
269686 }
270687
271 void
272 connector_get_sample_info_from_msg (GByteArray * info_msg, gint * id,
688 static gint
689 connector_get_smplrw_info_from_msg (GByteArray * info_msg, guint32 * id,
273690 guint * size)
274691 {
275 if (!connector_get_msg_status (info_msg))
692 if (connector_get_msg_status (info_msg))
276693 {
277694 if (id)
278695 {
279 *id = -1;
696 *id = be32toh (*((guint32 *) & info_msg->data[6]));
697 }
698 if (size)
699 {
700 *size = be32toh (*((guint32 *) & info_msg->data[10]));
280701 }
281702 }
282703 else
283704 {
284705 if (id)
285706 {
286 *id = be32toh (*((uint32_t *) & info_msg->data[6]));
287 }
288 if (size)
289 {
290 *size = be32toh (*((uint32_t *) & info_msg->data[10]));
291 }
292 }
707 return -EIO;
708 }
709 }
710
711 return 0;
293712 }
294713
295714 static GByteArray *
296 connector_new_msg_data (const guint8 * data, guint len)
715 connector_new_msg (const guint8 * data, guint len)
297716 {
298717 GByteArray *msg = g_byte_array_new ();
299718
306725 static GByteArray *
307726 connector_new_msg_uint8 (const guint8 * data, guint len, guint8 type)
308727 {
309 GByteArray *msg = connector_new_msg_data (data, len);
728 GByteArray *msg = connector_new_msg (data, len);
310729
311730 g_byte_array_append (msg, &type, 1);
312731
316735 static GByteArray *
317736 connector_new_msg_path (const guint8 * data, guint len, const gchar * path)
318737 {
319 GByteArray *msg = connector_new_msg_data (data, len);
320
321 g_byte_array_append (msg, (guchar *) path, strlen (path));
322 g_byte_array_append (msg, (guchar *) "\0", 1);
738 GByteArray *msg;
739 gchar *path_cp1252 = connector_get_cp1252 (path);
740
741 if (!path_cp1252)
742 {
743 return NULL;
744 }
745
746 msg = connector_new_msg (data, len);
747 g_byte_array_append (msg, (guchar *) path_cp1252, strlen (path_cp1252) + 1);
748 g_free (path_cp1252);
323749
324750 return msg;
325751 }
326752
327753 static GByteArray *
328 connector_new_msg_dir_list (const gchar * path)
329 {
330 return connector_new_msg_path (INQ_LS_DIR_TEMPLATE,
331 sizeof (INQ_LS_DIR_TEMPLATE), path);
754 connector_new_msg_close_common_read (const guint8 * data, guint len, guint id)
755 {
756 guint32 aux32;
757 GByteArray *msg = connector_new_msg (data, len);
758
759 aux32 = htobe32 (id);
760 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
761 return msg;
332762 }
333763
334764 static GByteArray *
335 connector_new_msg_open_file_read (const gchar * path)
336 {
337 return connector_new_msg_path (INQ_OPEN_FILE_READ_TEMPLATE,
338 sizeof (INQ_OPEN_FILE_READ_TEMPLATE), path);
765 connector_new_msg_close_sample_read (guint id)
766 {
767 return
768 connector_new_msg_close_common_read (FS_SAMPLE_CLOSE_FILE_READER_REQUEST,
769 sizeof
770 (FS_SAMPLE_CLOSE_FILE_READER_REQUEST),
771 id);
339772 }
340773
341774 static GByteArray *
342 connector_new_msg_new_dir (const gchar * path)
343 {
344 return connector_new_msg_path (INQ_NEW_DIR_TEMPLATE,
345 sizeof (INQ_NEW_DIR_TEMPLATE), path);
775 connector_new_msg_close_raw_read (guint id)
776 {
777 return
778 connector_new_msg_close_common_read (FS_RAW_CLOSE_FILE_READER_REQUEST,
779 sizeof
780 (FS_RAW_CLOSE_FILE_READER_REQUEST),
781 id);
346782 }
347783
348784 static GByteArray *
349 connector_new_msg_close_file_read (gint id)
350 {
351 uint32_t aux32;
352 GByteArray *msg = connector_new_msg_data (INQ_CLOSE_FILE_READ_TEMPLATE,
785 connector_new_msg_open_common_write (const guint8 * data, guint len,
786 const gchar * path, guint bytes)
787 {
788 guint32 aux32;
789 GByteArray *msg = connector_new_msg_path (data, len, path);
790
791 aux32 = htobe32 (bytes);
792 memcpy (&msg->data[5], &aux32, sizeof (guint32));
793
794 return msg;
795 }
796
797 static GByteArray *
798 connector_new_msg_open_sample_write (const gchar * path, guint bytes)
799 {
800 return
801 connector_new_msg_open_common_write (FS_SAMPLE_OPEN_FILE_WRITER_REQUEST,
802 sizeof
803 (FS_SAMPLE_OPEN_FILE_WRITER_REQUEST),
804 path,
805 bytes +
806 sizeof (struct
807 elektron_sample_info));
808 }
809
810 static GByteArray *
811 connector_new_msg_open_raw_write (const gchar * path, guint bytes)
812 {
813 return connector_new_msg_open_common_write (FS_RAW_OPEN_FILE_WRITER_REQUEST,
814 sizeof
815 (FS_RAW_OPEN_FILE_WRITER_REQUEST),
816 path, bytes);
817 }
818
819
820 static GByteArray *
821 connector_new_msg_list (const gchar * path, int32_t start_index,
822 int32_t end_index, gboolean all)
823 {
824 guint32 aux32;
825 guint8 aux8;
826 GByteArray *msg = connector_new_msg_path (DATA_LIST_REQUEST,
827 sizeof (DATA_LIST_REQUEST),
828 path);
829
830 aux32 = htobe32 (start_index);
831 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
832 aux32 = htobe32 (end_index);
833 g_byte_array_append (msg, (guchar *) & aux32, sizeof (guint32));
834 aux8 = all;
835 g_byte_array_append (msg, (guchar *) & aux8, sizeof (guint8));
836
837 return msg;
838 }
839
840 static GByteArray *
841 connector_new_msg_write_sample_blk (guint id, GByteArray * sample,
842 guint * total, guint seq, void *data)
843 {
844 guint32 aux32;
845 guint16 aux16, *aux16p;
846 int i, consumed, bytes_blk;
847 struct sample_loop_data *sample_loop_data = data;
848 struct elektron_sample_info elektron_sample_info;
849 GByteArray *msg = connector_new_msg (FS_SAMPLE_WRITE_FILE_REQUEST,
850 sizeof (FS_SAMPLE_WRITE_FILE_REQUEST));
851
852
853 aux32 = htobe32 (id);
854 memcpy (&msg->data[5], &aux32, sizeof (guint32));
855 aux32 = htobe32 (DATA_TRANSF_BLOCK_BYTES * seq);
856 memcpy (&msg->data[13], &aux32, sizeof (guint32));
857
858 bytes_blk = DATA_TRANSF_BLOCK_BYTES;
859 consumed = 0;
860
861 if (seq == 0)
862 {
863 elektron_sample_info.type = 0;
864 elektron_sample_info.sample_len_bytes = htobe32 (sample->len);
865 elektron_sample_info.sample_rate = htobe32 (ELEKTRON_SAMPLE_RATE);
866 elektron_sample_info.loop_start = htobe32 (sample_loop_data->start);
867 elektron_sample_info.loop_end = htobe32 (sample_loop_data->end);
868 elektron_sample_info.loop_type = htobe32 (ELEKTRON_LOOP_TYPE);
869 memset (&elektron_sample_info.padding, 0,
870 sizeof (guint32) * ELEKTRON_SAMPLE_INFO_PAD_I32_LEN);
871
872 g_byte_array_append (msg, (guchar *) & elektron_sample_info,
873 sizeof (struct elektron_sample_info));
874
875 consumed = sizeof (struct elektron_sample_info);
876 bytes_blk -= consumed;
877 }
878
879 i = 0;
880 aux16p = (guint16 *) & sample->data[*total];
881 while (i < bytes_blk && *total < sample->len)
882 {
883 aux16 = htobe16 (*aux16p);
884 g_byte_array_append (msg, (guint8 *) & aux16, sizeof (guint16));
885 aux16p++;
886 (*total) += sizeof (guint16);
887 consumed += sizeof (guint16);
888 i += sizeof (guint16);
889 }
890
891 aux32 = htobe32 (consumed);
892 memcpy (&msg->data[9], &aux32, sizeof (guint32));
893
894 return msg;
895 }
896
897 static GByteArray *
898 connector_new_msg_write_raw_blk (guint id, GByteArray * raw, guint * total,
899 guint seq, void *data)
900 {
901 gint len;
902 guint32 aux32;
903 GByteArray *msg = connector_new_msg (FS_RAW_WRITE_FILE_REQUEST,
904 sizeof (FS_RAW_WRITE_FILE_REQUEST));
905
906 aux32 = htobe32 (id);
907 memcpy (&msg->data[5], &aux32, sizeof (guint32));
908 aux32 = htobe32 (DATA_TRANSF_BLOCK_BYTES * seq);
909 memcpy (&msg->data[13], &aux32, sizeof (guint32));
910
911 len = raw->len - *total;
912 len = len > DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : len;
913 g_byte_array_append (msg, &raw->data[*total], len);
914 (*total) += len;
915
916 aux32 = htobe32 (len);
917 memcpy (&msg->data[9], &aux32, sizeof (guint32));
918
919 return msg;
920 }
921
922 static GByteArray *
923 connector_new_msg_close_common_write (const guint8 * data, guint len,
924 guint id, guint bytes)
925 {
926 guint32 aux32;
927 GByteArray *msg = connector_new_msg (data, len);
928
929 aux32 = htobe32 (id);
930 memcpy (&msg->data[5], &aux32, sizeof (guint32));
931 aux32 = htobe32 (bytes);
932 memcpy (&msg->data[9], &aux32, sizeof (guint32));
933
934 return msg;
935 }
936
937 static GByteArray *
938 connector_new_msg_close_sample_write (guint id, guint bytes)
939 {
940 return
941 connector_new_msg_close_common_write (FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST,
942 sizeof
943 (FS_SAMPLE_CLOSE_FILE_WRITER_REQUEST),
944 id,
945 bytes +
946 sizeof (struct
947 elektron_sample_info));
948 }
949
950 static GByteArray *
951 connector_new_msg_close_raw_write (guint id, guint bytes)
952 {
953 return
954 connector_new_msg_close_common_write (FS_RAW_CLOSE_FILE_WRITER_REQUEST,
955 sizeof
956 (FS_RAW_CLOSE_FILE_WRITER_REQUEST),
957 id, bytes);
958 }
959
960 static GByteArray *
961 connector_new_msg_read_common_blk (const guint8 * data, guint len, guint id,
962 guint start, guint size)
963 {
964 guint32 aux;
965 GByteArray *msg = connector_new_msg (data, len);
966
967 aux = htobe32 (id);
968 memcpy (&msg->data[5], &aux, sizeof (guint32));
969 aux = htobe32 (size);
970 memcpy (&msg->data[9], &aux, sizeof (guint32));
971 aux = htobe32 (start);
972 memcpy (&msg->data[13], &aux, sizeof (guint32));
973
974 return msg;
975 }
976
977 static GByteArray *
978 connector_new_msg_read_sample_blk (guint id, guint start, guint size)
979 {
980 return connector_new_msg_read_common_blk (FS_SAMPLE_READ_FILE_REQUEST,
353981 sizeof
354 (INQ_CLOSE_FILE_READ_TEMPLATE));
355
356 aux32 = htobe32 (id);
357 g_byte_array_append (msg, (guchar *) & aux32, sizeof (uint32_t));
358 return msg;
982 (FS_SAMPLE_READ_FILE_REQUEST), id,
983 start, size);
359984 }
360985
361986 static GByteArray *
362 connector_new_msg_open_file_write (const gchar * path, guint frames)
363 {
364 uint32_t aux32;
365 GByteArray *msg = connector_new_msg_path (INQ_OPEN_FILE_WRITE_TEMPLATE,
366 sizeof
367 (INQ_OPEN_FILE_WRITE_TEMPLATE),
368 path);
369
370 aux32 = htobe32 ((frames + 32) * 2);
371 memcpy (&msg->data[5], &aux32, sizeof (uint32_t));
372
373 return msg;
987 connector_new_msg_read_raw_blk (guint id, guint start, guint size)
988 {
989 return connector_new_msg_read_common_blk (FS_RAW_READ_FILE_REQUEST,
990 sizeof (FS_RAW_READ_FILE_REQUEST),
991 id, start, size);
374992 }
375993
376994 static GByteArray *
377 connector_new_msg_write_file_blk (guint id, gshort ** data, guint frames,
378 ssize_t * total, guint seq)
379 {
380 uint32_t aux32;
381 uint16_t aux16;
382 int i, consumed, frames_blck;
383 GByteArray *msg;
384
385 if (seq == 0)
386 {
387 msg = connector_new_msg_data (INQ_FILE_WRITE_BLK_TEMPLATE_1ST,
388 sizeof (INQ_FILE_WRITE_BLK_TEMPLATE_1ST));
389 frames_blck = 4064;
390 }
391 else
392 {
393 msg = connector_new_msg_data (INQ_FILE_WRITE_BLK_TEMPLATE_NTH,
394 sizeof (INQ_FILE_WRITE_BLK_TEMPLATE_NTH));
395 frames_blck = 4096;
396 }
397
398 i = 0;
399 consumed = 0;
400 while (i < frames_blck && *total < frames)
401 {
402 aux16 = htobe16 (**data);
403 g_byte_array_append (msg, (guchar *) & aux16, sizeof (uint16_t));
404 (*data)++;
405 (*total)++;
406 consumed++;
407 i++;
408 }
409
410 aux32 = htobe32 (id);
411 memcpy (&msg->data[5], &aux32, sizeof (uint32_t));
412
413 if (seq == 0)
414 {
415 aux32 = htobe32 ((consumed + 32) * 2);
416 memcpy (&msg->data[9], &aux32, sizeof (uint32_t));
417 aux32 = htobe32 (frames * sizeof (gshort));
418 memcpy (&msg->data[21], &aux32, sizeof (uint32_t));
419 aux32 = htobe32 (frames - 1);
420 memcpy (&msg->data[33], &aux32, sizeof (uint32_t));
421 }
422 else
423 {
424 aux32 = htobe32 (consumed * 2);
425 memcpy (&msg->data[9], &aux32, sizeof (uint32_t));
426 aux32 = htobe32 (0x2000 * seq);
427 memcpy (&msg->data[13], &aux32, sizeof (uint32_t));
428 }
429
430 return msg;
431 }
432
433 static GByteArray *
434 connector_new_msg_close_file_write (guint id, guint frames)
435 {
436 uint32_t aux32;
437 GByteArray *msg = connector_new_msg_data (INQ_CLOSE_FILE_WRITE_TEMPLATE,
438 sizeof
439 (INQ_CLOSE_FILE_WRITE_TEMPLATE));
440
441 aux32 = htobe32 (id);
442 memcpy (&msg->data[5], &aux32, sizeof (uint32_t));
443 aux32 = htobe32 ((frames + 32) * 2);
444 memcpy (&msg->data[9], &aux32, sizeof (uint32_t));
445
446 return msg;
447 }
448
449 static GByteArray *
450 connector_new_msg_read_file_blk (guint id, guint start, guint size)
451 {
452 uint32_t aux;
453 GByteArray *msg = connector_new_msg_data (INQ_FILE_READ_BLK_TEMPLATE,
454 sizeof
455 (INQ_FILE_READ_BLK_TEMPLATE));
456
457 aux = htobe32 (id);
458 memcpy (&msg->data[5], &aux, sizeof (uint32_t));
459 aux = htobe32 (size);
460 memcpy (&msg->data[9], &aux, sizeof (uint32_t));
461 aux = htobe32 (start);
462 memcpy (&msg->data[13], &aux, sizeof (uint32_t));
463
464 return msg;
465 }
466
467 static GByteArray *
468 connector_sysex_to_msg (GByteArray * sysex)
995 connector_raw_to_msg (GByteArray * sysex)
469996 {
470997 GByteArray *msg;
471998 GByteArray *payload;
4941021 if (!connector->outputp)
4951022 {
4961023 error_print ("Output port is NULL\n");
497 return -1;
1024 return -ENOTCONN;
4981025 }
4991026
5001027 snd_rawmidi_read (connector->inputp, NULL, 0); // trigger reading
5021029 tx_len = snd_rawmidi_write (connector->outputp, data, len);
5031030 if (tx_len < 0)
5041031 {
505 error_print ("Error while sending message. %s.\n", g_strerror (errno));
1032 error_print ("Error while writing to device: %s\n",
1033 snd_strerror (tx_len));
5061034 connector_destroy (connector);
507 return tx_len;
5081035 }
5091036 return tx_len;
5101037 }
5111038
512 ssize_t
513 connector_tx_sysex (struct connector *connector, GByteArray * data,
1039 gint
1040 connector_tx_sysex (struct connector *connector,
5141041 struct connector_sysex_transfer *transfer)
5151042 {
5161043 ssize_t tx_len;
5171044 guint total;
5181045 guint len;
5191046 guchar *b;
520 ssize_t ret = data->len;
1047 gint res = 0;
5211048
5221049 transfer->status = SENDING;
5231050
524 b = data->data;
1051 b = transfer->raw->data;
5251052 total = 0;
526 while (total < data->len && transfer->active)
527 {
528 len = data->len - total;
1053 while (total < transfer->raw->len && transfer->active)
1054 {
1055 len = transfer->raw->len - total;
5291056 if (len > BUFF_SIZE)
5301057 {
5311058 len = BUFF_SIZE;
5341061 tx_len = connector_tx_raw (connector, b, len);
5351062 if (tx_len < 0)
5361063 {
537 ret = tx_len;
538 errno = EIO;
1064 res = tx_len;
5391065 break;
5401066 }
5411067 b += len;
5441070
5451071 transfer->active = FALSE;
5461072 transfer->status = FINISHED;
547 return ret;
548 }
549
550 static ssize_t
1073 return res;
1074 }
1075
1076 static gint
5511077 connector_tx (struct connector *connector, const GByteArray * msg)
5521078 {
553 ssize_t ret;
554 uint16_t aux;
555 GByteArray *sysex;
1079 gint res;
1080 guint16 aux;
1081 gchar *text;
5561082 struct connector_sysex_transfer transfer;
557 gchar *text;
5581083
5591084 aux = htobe16 (connector->seq);
560 memcpy (msg->data, &aux, sizeof (uint16_t));
1085 memcpy (msg->data, &aux, sizeof (guint16));
5611086 if (connector->seq == USHRT_MAX)
5621087 {
5631088 connector->seq = 0;
5681093 }
5691094
5701095 transfer.active = TRUE;
571 sysex = connector_msg_to_sysex (msg);
572
573 ret = connector_tx_sysex (connector, sysex, &transfer);
574
575 if (ret >= 0)
1096 transfer.raw = connector_msg_to_raw (msg);
1097
1098 res = connector_tx_sysex (connector, &transfer);
1099 if (!res)
5761100 {
5771101 if (debug_level > 1)
5781102 {
579 text = debug_get_hex_msg (sysex);
580 debug_print (2, "Raw message sent (%d): %s\n", sysex->len, text);
1103 text = debug_get_hex_msg (transfer.raw);
1104 debug_print (2, "Raw message sent (%d): %s\n", transfer.raw->len,
1105 text);
5811106 free (text);
5821107 }
5831108
5861111 free (text);
5871112 }
5881113
589 free_msg (sysex);
590 return ret;
1114 free_msg (transfer.raw);
1115 return res;
5911116 }
5921117
5931118 void
6281153 if (!connector->inputp)
6291154 {
6301155 error_print ("Input port is NULL\n");
631 return -1;
1156 return -ENOTCONN;
6321157 }
6331158
6341159 total_time = 0;
6691194 &revents)) < 0)
6701195 {
6711196 error_print ("Error while getting poll events. %s.\n",
672 g_strerror (errno));
1197 snd_strerror (err));
6731198 connector_destroy (connector);
6741199 return err;
6751200 }
7021227
7031228 if (rx_len < 0)
7041229 {
705 error_print ("Error while receiving message. %s.\n",
706 g_strerror (errno));
1230 error_print ("Error while reading from device: %s\n",
1231 snd_strerror (rx_len));
7071232 connector_destroy (connector);
7081233 break;
7091234 }
7201245 return rx_len;
7211246 }
7221247
723 GByteArray *
1248 gint
7241249 connector_rx_sysex (struct connector *connector,
7251250 struct connector_sysex_transfer *transfer)
7261251 {
7271252 gint i;
7281253 guint8 *b;
729 GByteArray *sysex = g_byte_array_new ();
1254 gint res = 0;
7301255
7311256 transfer->status = WAITING;
1257 transfer->raw = g_byte_array_new ();
7321258
7331259 i = 0;
7341260 if (connector->rx_len < 0)
7471273
7481274 if (connector->rx_len == -ENODATA)
7491275 {
750 errno = ENODATA;
1276 res = -ENODATA;
7511277 goto error;
7521278 }
7531279
7541280 if (connector->rx_len < 0)
7551281 {
756 errno = EIO;
1282 res = -EIO;
7571283 goto error;
7581284 }
7591285
7731299 }
7741300 }
7751301
776 g_byte_array_append (sysex, b, 1);
1302 g_byte_array_append (transfer->raw, b, 1);
7771303 b++;
7781304 i++;
7791305 transfer->status = RECEIVING;
7931319
7941320 if (connector->rx_len < 0)
7951321 {
796 errno = EIO;
1322 res = -EIO;
7971323 goto error;
7981324 }
7991325
8051331 {
8061332 if (!connector_is_rt_msg (b, 1))
8071333 {
808 g_byte_array_append (sysex, b, 1);
1334 g_byte_array_append (transfer->raw, b, 1);
8091335 }
8101336 b++;
8111337 i++;
8131339
8141340 if (i < connector->rx_len)
8151341 {
816 g_byte_array_append (sysex, b, 1);
1342 g_byte_array_append (transfer->raw, b, 1);
8171343 connector->rx_len = connector->rx_len - i - 1;
8181344 if (connector->rx_len > 0)
8191345 {
8281354 goto end;
8291355
8301356 error:
831 free_msg (sysex);
832 sysex = NULL;
1357 free_msg (transfer->raw);
1358 transfer->raw = NULL;
8331359 end:
8341360 transfer->active = FALSE;
8351361 transfer->status = FINISHED;
836 return sysex;
1362 return res;
8371363 }
8381364
8391365 static GByteArray *
8401366 connector_rx (struct connector *connector)
8411367 {
1368 gchar *text;
8421369 GByteArray *msg;
843 GByteArray *sysex;
8441370 struct connector_sysex_transfer transfer;
845 gchar *text;
8461371
8471372 transfer.active = TRUE;
8481373 transfer.timeout = SYSEX_TIMEOUT;
8491374 transfer.batch = FALSE;
8501375
851 sysex = connector_rx_sysex (connector, &transfer);
852 if (!sysex)
1376 if (connector_rx_sysex (connector, &transfer))
8531377 {
8541378 return NULL;
8551379 }
856 while (sysex->len < 12
857 || (sysex->len >= 12
858 && (sysex->data[0] != MSG_HEADER[0]
859 || sysex->data[1] != MSG_HEADER[1]
860 || sysex->data[2] != MSG_HEADER[2]
861 || sysex->data[3] != MSG_HEADER[3]
862 || sysex->data[4] != MSG_HEADER[4]
863 || sysex->data[5] != MSG_HEADER[5])))
1380 while (transfer.raw->len < 12
1381 || (transfer.raw->len >= 12
1382 && (transfer.raw->data[0] != MSG_HEADER[0]
1383 || transfer.raw->data[1] != MSG_HEADER[1]
1384 || transfer.raw->data[2] != MSG_HEADER[2]
1385 || transfer.raw->data[3] != MSG_HEADER[3]
1386 || transfer.raw->data[4] != MSG_HEADER[4]
1387 || transfer.raw->data[5] != MSG_HEADER[5])))
8641388 {
8651389 if (debug_level > 1)
8661390 {
867 text = debug_get_hex_msg (sysex);
868 debug_print (2, "Message skipped (%d): %s\n", sysex->len, text);
1391 text = debug_get_hex_msg (transfer.raw);
1392 debug_print (2, "Message skipped (%d): %s\n", transfer.raw->len,
1393 text);
8691394 free (text);
8701395 }
871 free_msg (sysex);
1396 free_msg (transfer.raw);
8721397
8731398 transfer.active = TRUE;
874 sysex = connector_rx_sysex (connector, &transfer);
875 if (!sysex)
1399 if (connector_rx_sysex (connector, &transfer))
8761400 {
8771401 return NULL;
8781402 }
8801404
8811405 if (debug_level > 1)
8821406 {
883 text = debug_get_hex_msg (sysex);
884 debug_print (2, "Raw message received (%d): %s\n", sysex->len, text);
1407 text = debug_get_hex_msg (transfer.raw);
1408 debug_print (2, "Raw message received (%d): %s\n", transfer.raw->len,
1409 text);
8851410 free (text);
8861411 }
8871412
888 msg = connector_sysex_to_msg (sysex);
1413 msg = connector_raw_to_msg (transfer.raw);
8891414 if (msg)
8901415 {
8911416 text = debug_get_hex_msg (msg);
8931418 free (text);
8941419 }
8951420
896 free_msg (sysex);
1421 free_msg (transfer.raw);
8971422 return msg;
8981423 }
8991424
9221447 return rx_msg;
9231448 }
9241449
925 struct connector_dir_iterator *
926 connector_read_dir (struct connector *connector, const gchar * dir)
927 {
1450 static gint
1451 connector_read_common_dir (struct item_iterator *iter, const gchar * dir,
1452 void *data, const guint8 msg[], int size,
1453 fs_init_iter_func init_iter, enum connector_fs fs)
1454 {
1455 gboolean cache;
9281456 GByteArray *tx_msg;
9291457 GByteArray *rx_msg;
930 gchar *dir_cp1252 = g_convert (dir, -1, "CP1252", "UTF8", NULL, NULL, NULL);
931
932 if (!dir_cp1252)
933 {
934 errno = EINVAL;
935 return NULL;
936 }
937
938 tx_msg = connector_new_msg_dir_list (dir_cp1252);
939 g_free (dir_cp1252);
940
941 rx_msg = connector_tx_and_rx (connector, tx_msg);
1458 struct connector *connector = data;
1459
1460 g_mutex_lock (&connector->mutex);
1461 cache = connector->dir_cache != NULL;
1462 rx_msg = cache ? g_hash_table_lookup (connector->dir_cache, dir) : NULL;
1463 g_mutex_unlock (&connector->mutex);
1464
9421465 if (!rx_msg)
9431466 {
944 return NULL;
945 }
946
947 if (rx_msg->len == 5
948 && connector_get_path_type (connector, dir) != ELEKTROID_DIR)
949 {
950 free_msg (rx_msg);
951 errno = ENOTDIR;
952 return NULL;
953 }
954
955 return connector_new_dir_iterator (rx_msg);
956 }
957
958 static gchar
959 connector_get_path_type (struct connector *connector, const gchar * path)
1467 tx_msg = connector_new_msg_path (msg, size, dir);
1468 if (!tx_msg)
1469 {
1470 return -EINVAL;
1471 }
1472
1473 rx_msg = connector_tx_and_rx (connector, tx_msg);
1474 if (!rx_msg)
1475 {
1476 return -EIO;
1477 }
1478
1479 g_mutex_lock (&connector->mutex);
1480 cache = connector->dir_cache != NULL;
1481 if (cache)
1482 {
1483 gchar *key = g_strdup (dir);
1484 g_hash_table_insert (connector->dir_cache, key, rx_msg);
1485 }
1486 g_mutex_unlock (&connector->mutex);
1487
1488 if (rx_msg->len == 5
1489 && connector_get_path_type (connector, dir,
1490 init_iter) != ELEKTROID_DIR)
1491 {
1492 if (!cache)
1493 {
1494 free_msg (rx_msg);
1495 }
1496 return -ENOTDIR;
1497 }
1498 }
1499
1500 return connector_init_iterator (iter, rx_msg, connector_next_smplrw_entry,
1501 fs, cache);
1502 }
1503
1504 static gint
1505 connector_read_samples_dir (struct item_iterator *iter, const gchar * dir,
1506 void *data)
1507 {
1508 return connector_read_common_dir (iter, dir, data,
1509 FS_SAMPLE_READ_DIR_REQUEST,
1510 sizeof (FS_SAMPLE_READ_DIR_REQUEST),
1511 connector_read_samples_dir, FS_SAMPLES);
1512 }
1513
1514 static gint
1515 connector_read_raw_dir (struct item_iterator *iter, const gchar * dir,
1516 void *data)
1517 {
1518 return connector_read_common_dir (iter, dir, data, FS_RAW_READ_DIR_REQUEST,
1519 sizeof (FS_RAW_READ_DIR_REQUEST),
1520 connector_read_raw_dir, FS_RAW_ALL);
1521 }
1522
1523 static enum item_type
1524 connector_get_path_type (struct connector *connector, const gchar * path,
1525 fs_init_iter_func init_iter)
9601526 {
9611527 gchar *name_copy;
9621528 gchar *parent_copy;
9631529 gchar *name;
9641530 gchar *parent;
965 gchar res;
966 struct connector_dir_iterator *d_iter;
1531 enum item_type res;
1532 struct item_iterator iter;
9671533
9681534 if (strcmp (path, "/") == 0)
9691535 {
9741540 parent_copy = strdup (path);
9751541 name = basename (name_copy);
9761542 parent = dirname (parent_copy);
977 d_iter = connector_read_dir (connector, parent);
9781543 res = ELEKTROID_NONE;
979 if (d_iter)
980 {
981 while (!connector_get_next_dentry (d_iter))
982 {
983 if (strcmp (name, d_iter->dentry) == 0)
1544 if (!init_iter (&iter, parent, connector))
1545 {
1546 while (!next_item_iterator (&iter))
1547 {
1548 if (strcmp (name, iter.item.name) == 0)
9841549 {
985 res = d_iter->type;
1550 res = iter.item.type;
9861551 break;
9871552 }
9881553 }
989 connector_free_dir_iterator (d_iter);
1554 free_item_iterator (&iter);
9901555 }
9911556
9921557 g_free (name_copy);
9951560 }
9961561
9971562 static gint
998 connector_rename_file (struct connector *connector, const gchar * old,
999 const gchar * new)
1563 connector_src_dst_common (struct connector *connector,
1564 const gchar * src, const gchar * dst,
1565 const guint8 * data, guint len)
10001566 {
10011567 gint res;
10021568 GByteArray *rx_msg;
1003 GByteArray *tx_msg = connector_new_msg_data (INQ_RENAME_TEMPLATE,
1004 sizeof (INQ_RENAME_TEMPLATE));
1005 gchar *new_cp1252 = g_convert (new, -1, "CP1252", "UTF8", NULL, NULL, NULL);
1006 if (!new_cp1252)
1007 {
1008 errno = EINVAL;
1009 return -1;
1010 }
1011
1012 gchar *old_cp1252 = g_convert (old, -1, "CP1252", "UTF8", NULL, NULL, NULL);
1013 if (!old_cp1252)
1014 {
1015 g_free (new_cp1252);
1016 errno = EINVAL;
1017 return -1;
1018 }
1019
1020 g_byte_array_append (tx_msg, (guchar *) old_cp1252, strlen (old_cp1252));
1021 g_byte_array_append (tx_msg, (guchar *) "\0", 1);
1022 g_byte_array_append (tx_msg, (guchar *) new_cp1252, strlen (new_cp1252));
1023 g_byte_array_append (tx_msg, (guchar *) "\0", 1);
1024
1025 g_free (old_cp1252);
1026 g_free (new_cp1252);
1569 GByteArray *tx_msg = connector_new_msg (data, len);
1570
1571 gchar *dst_cp1252 = connector_get_cp1252 (dst);
1572 if (!dst_cp1252)
1573 {
1574 return -EINVAL;
1575 }
1576
1577 gchar *src_cp1252 = connector_get_cp1252 (src);
1578 if (!src_cp1252)
1579 {
1580 g_free (dst_cp1252);
1581 return -EINVAL;
1582 }
1583
1584 g_byte_array_append (tx_msg, (guchar *) src_cp1252,
1585 strlen (src_cp1252) + 1);
1586 g_byte_array_append (tx_msg, (guchar *) dst_cp1252,
1587 strlen (dst_cp1252) + 1);
1588
1589 g_free (src_cp1252);
1590 g_free (dst_cp1252);
10271591
10281592 rx_msg = connector_tx_and_rx (connector, tx_msg);
10291593 if (!rx_msg)
10301594 {
1031 return -1;
1595 return -EIO;
10321596 }
10331597 //Response: x, x, x, x, 0xa1, [0 (error), 1 (success)]...
10341598 if (connector_get_msg_status (rx_msg))
10371601 }
10381602 else
10391603 {
1040 res = -1;
1041 errno = EPERM;
1042 error_print ("%s\n", g_strerror (errno));
1604 res = -EPERM;
1605 error_print ("%s (%s)\n", snd_strerror (res),
1606 connector_get_msg_string (rx_msg));
10431607 }
10441608 free_msg (rx_msg);
10451609
10461610 return res;
10471611 }
10481612
1049 gint
1050 connector_rename (struct connector *connector, const gchar * old,
1051 const gchar * new)
1052 {
1053 gchar type;
1613 static gint
1614 connector_rename_sample_file (struct connector *connector, const gchar * src,
1615 const gchar * dst)
1616 {
1617 return connector_src_dst_common (connector, src, dst,
1618 FS_SAMPLE_RENAME_FILE_REQUEST,
1619 sizeof (FS_SAMPLE_RENAME_FILE_REQUEST));
1620 }
1621
1622 static gint
1623 connector_rename_raw_file (struct connector *connector, const gchar * src,
1624 const gchar * dst)
1625 {
1626 return connector_src_dst_common (connector, src, dst,
1627 FS_RAW_RENAME_FILE_REQUEST,
1628 sizeof (FS_RAW_RENAME_FILE_REQUEST));
1629 }
1630
1631 static gint
1632 connector_move_common_item (const gchar * src, const gchar * dst, void *data,
1633 fs_init_iter_func init_iter,
1634 connector_src_dst_func mv, fs_path_func mkdir,
1635 connector_path_func rmdir)
1636 {
1637 enum item_type type;
10541638 gint res;
1055 gchar *old_plus;
1056 gchar *new_plus;
1057 struct connector_dir_iterator *d_iter;
1639 gchar *src_plus;
1640 gchar *dst_plus;
1641 struct item_iterator iter;
1642 struct connector *connector = data;
10581643
10591644 //Renaming is not implemented for directories so we need to implement it.
1060 type = connector_get_path_type (connector, old);
1061
1645
1646 debug_print (1, "Renaming remotely from %s to %s...\n", src, dst);
1647
1648 type = connector_get_path_type (connector, src, init_iter);
10621649 if (type == ELEKTROID_FILE)
10631650 {
1064 return connector_rename_file (connector, old, new);
1651 return mv (connector, src, dst);
10651652 }
10661653 else if (type == ELEKTROID_DIR)
10671654 {
1068 res = connector_create_dir (connector, new);
1655 res = mkdir (dst, connector);
10691656 if (res)
10701657 {
10711658 return res;
10721659 }
1073 d_iter = connector_read_dir (connector, old);
1074 if (d_iter)
1075 {
1076 while (!connector_get_next_dentry (d_iter) && !res)
1660 if (!init_iter (&iter, src, connector))
1661 {
1662 while (!next_item_iterator (&iter) && !res)
10771663 {
1078 old_plus = chain_path (old, d_iter->dentry);
1079 new_plus = chain_path (new, d_iter->dentry);
1080 res = connector_rename (connector, old_plus, new_plus);
1081 free (old_plus);
1082 free (new_plus);
1664 src_plus = chain_path (src, iter.item.name);
1665 dst_plus = chain_path (dst, iter.item.name);
1666 res =
1667 connector_move_common_item (src_plus, dst_plus, connector,
1668 init_iter, mv, mkdir, rmdir);
1669 free (src_plus);
1670 free (dst_plus);
10831671 }
1084 connector_free_dir_iterator (d_iter);
1672 free_item_iterator (&iter);
10851673 }
10861674 if (!res)
10871675 {
1088 res = connector_delete_dir (connector, old);
1676 res = rmdir (connector, src);
10891677 }
10901678 return res;
10911679 }
10921680 else
10931681 {
1094 errno = EBADF;
1095 return -1;
1096 }
1097 }
1098
1099 static gint
1100 connector_delete (struct connector *connector, const gchar * path,
1101 const guint8 * template, gint size)
1682 return -EBADF;
1683 }
1684 }
1685
1686 static gint
1687 connector_path_common (struct connector *connector, const gchar * path,
1688 const guint8 * template, gint size)
11021689 {
11031690 gint res;
11041691 GByteArray *rx_msg;
11051692 GByteArray *tx_msg;
1106 gchar *path_cp1252 =
1107 g_convert (path, -1, "CP1252", "UTF8", NULL, NULL, NULL);
1108
1109 if (!path_cp1252)
1110 {
1111 errno = EINVAL;
1112 return -1;
1113 }
1114
1115 tx_msg = connector_new_msg_path (template, size, path_cp1252);
1116 g_free (path_cp1252);
1693
1694 tx_msg = connector_new_msg_path (template, size, path);
1695 if (!tx_msg)
1696 {
1697 return -EINVAL;
1698 }
11171699
11181700 rx_msg = connector_tx_and_rx (connector, tx_msg);
11191701 if (!rx_msg)
11201702 {
1121 return -1;
1703 return -EIO;
11221704 }
11231705 //Response: x, x, x, x, 0xX0, [0 (error), 1 (success)]...
11241706 if (connector_get_msg_status (rx_msg))
11271709 }
11281710 else
11291711 {
1130 res = -1;
1131 errno = EPERM;
1132 error_print ("%s\n", g_strerror (errno));
1712 res = -EPERM;
1713 error_print ("%s (%s)\n", snd_strerror (res),
1714 connector_get_msg_string (rx_msg));
11331715 }
11341716 free_msg (rx_msg);
11351717
11361718 return res;
11371719 }
11381720
1139 gint
1140 connector_delete_file (struct connector *connector, const gchar * path)
1141 {
1142 return connector_delete (connector, path, INQ_DELETE_FILE_TEMPLATE,
1143 sizeof (INQ_DELETE_FILE_TEMPLATE));
1144 }
1145
1146 gint
1147 connector_delete_dir (struct connector *connector, const gchar * path)
1148 {
1149 return connector_delete (connector, path, INQ_DELETE_DIR_TEMPLATE,
1150 sizeof (INQ_DELETE_DIR_TEMPLATE));
1151 }
1152
1153 ssize_t
1154 connector_upload (struct connector *connector, GArray * sample,
1155 gchar * path, struct connector_sample_transfer *transfer,
1156 void (*progress) (gdouble))
1157 {
1721 static gint
1722 connector_delete_sample (struct connector *connector, const gchar * path)
1723 {
1724 return connector_path_common (connector, path,
1725 FS_SAMPLE_DELETE_FILE_REQUEST,
1726 sizeof (FS_SAMPLE_DELETE_FILE_REQUEST));
1727 }
1728
1729 static gint
1730 connector_delete_samples_dir (struct connector *connector, const gchar * path)
1731 {
1732 return connector_path_common (connector, path, FS_SAMPLE_DELETE_DIR_REQUEST,
1733 sizeof (FS_SAMPLE_DELETE_DIR_REQUEST));
1734 }
1735
1736 //This adds back the extension ".mc-snd" that the device provides.
1737 static gchar *
1738 connector_add_ext_to_mc_snd (const gchar * path)
1739 {
1740 gchar *path_with_ext = malloc (PATH_MAX);
1741 snprintf (path_with_ext, PATH_MAX, "%s%s", path, ".mc-snd");
1742 return path_with_ext;
1743 }
1744
1745 static gint
1746 connector_delete_raw (struct connector *connector, const gchar * path)
1747 {
1748 gint ret;
1749 gchar *path_with_ext = connector_add_ext_to_mc_snd (path);
1750 ret = connector_path_common (connector, path_with_ext,
1751 FS_RAW_DELETE_FILE_REQUEST,
1752 sizeof (FS_RAW_DELETE_FILE_REQUEST));
1753 g_free (path_with_ext);
1754 return ret;
1755 }
1756
1757 static gint
1758 connector_delete_raw_dir (struct connector *connector, const gchar * path)
1759 {
1760 return connector_path_common (connector, path, FS_RAW_DELETE_DIR_REQUEST,
1761 sizeof (FS_RAW_DELETE_DIR_REQUEST));
1762 }
1763
1764 static gint
1765 connector_move_samples_item (const gchar * src, const gchar * dst, void *data)
1766 {
1767 return connector_move_common_item (src, dst, data,
1768 connector_read_samples_dir,
1769 connector_rename_sample_file,
1770 connector_create_samples_dir,
1771 connector_delete_samples_dir);
1772 }
1773
1774 static gint
1775 connector_move_raw_item (const gchar * src, const gchar * dst, void *data)
1776 {
1777 gint ret;
1778 gchar *src_with_ext = connector_add_ext_to_mc_snd (src);
1779 ret = connector_move_common_item (src_with_ext, dst, data,
1780 connector_read_raw_dir,
1781 connector_rename_raw_file,
1782 connector_create_raw_dir,
1783 connector_delete_raw_dir);
1784 g_free (src_with_ext);
1785 return ret;
1786 }
1787
1788 static gint
1789 connector_delete_common_item (const gchar * path, void *data,
1790 fs_init_iter_func init_iter,
1791 connector_path_func rmdir,
1792 connector_path_func rm)
1793 {
1794 enum item_type type;
1795 gchar *new_path;
1796 struct item_iterator iter;
1797 struct connector *connector = data;
1798 gint res;
1799
1800 type = connector_get_path_type (connector, path, init_iter);
1801 if (type == ELEKTROID_FILE)
1802 {
1803 return rm (connector, path);
1804 }
1805 else if (type == ELEKTROID_DIR)
1806 {
1807 debug_print (1, "Deleting %s samples dir...\n", path);
1808
1809 if (init_iter (&iter, path, connector))
1810 {
1811 error_print ("Error while opening samples dir %s dir\n", path);
1812 }
1813 else
1814 {
1815 res = 0;
1816 while (!res && !next_item_iterator (&iter))
1817 {
1818 new_path = chain_path (path, iter.item.name);
1819 res = res
1820 || connector_delete_common_item (new_path, connector,
1821 init_iter, rmdir, rm);
1822 free (new_path);
1823 }
1824 free_item_iterator (&iter);
1825 }
1826 return res || rmdir (connector, path);
1827 }
1828 else
1829 {
1830 return -EBADF;
1831 }
1832 }
1833
1834 static gint
1835 connector_delete_samples_item (const gchar * path, void *data)
1836 {
1837 return connector_delete_common_item (path, data,
1838 connector_read_samples_dir,
1839 connector_delete_samples_dir,
1840 connector_delete_sample);
1841 }
1842
1843 static gint
1844 connector_delete_raw_item (const gchar * path, void *data)
1845 {
1846 return connector_delete_common_item (path, data,
1847 connector_read_raw_dir,
1848 connector_delete_raw_dir,
1849 connector_delete_raw);
1850 }
1851
1852 static gint
1853 connector_upload_smplrw (const gchar * path, GByteArray * input,
1854 struct job_control *control, void *data,
1855 connector_msg_path_len_func new_msg_open_write,
1856 connector_msg_write_blk_func new_msg_write_blk,
1857 connector_msg_id_len_func new_msg_close_write)
1858 {
1859 struct connector *connector = data;
11581860 GByteArray *tx_msg;
11591861 GByteArray *rx_msg;
1160 ssize_t transferred;
1161 gshort *data;
1162 gint id;
1862 guint transferred;
1863 guint32 id;
11631864 int i;
11641865 gboolean active;
1165 gchar *path_cp1252 =
1166 g_convert (path, -1, "CP1252", "UTF8", NULL, NULL, NULL);
1167
1168 if (!path_cp1252)
1169 {
1170 errno = EINVAL;
1171 return -1;
1172 }
1173
1174 //TODO: check if the file already exists? (Device makes no difference between creating a new file and creating an already existent file. The new file would be deleted if an upload is not sent, though.)
1175 //TODO: limit sample upload?
1176
1177 tx_msg = connector_new_msg_open_file_write (path_cp1252, sample->len);
1178 g_free (path_cp1252);
1866 gint res = 0;
1867
1868 //If the file already exists the device makes no difference between creating a new file and creating an already existent file.
1869 //Also, the new file would be discarded if an upload is not completed.
1870
1871 tx_msg = new_msg_open_write (path, input->len);
1872 if (!tx_msg)
1873 {
1874 return -EINVAL;
1875 }
1876
11791877 rx_msg = connector_tx_and_rx (connector, tx_msg);
11801878 if (!rx_msg)
11811879 {
1182 return -1;
1880 return -EIO;
11831881 }
11841882
11851883 //Response: x, x, x, x, 0xc0, [0 (error), 1 (success)], id, frames
1186 connector_get_sample_info_from_msg (rx_msg, &id, NULL);
1884 res = connector_get_smplrw_info_from_msg (rx_msg, &id, NULL);
1885 if (res)
1886 {
1887 error_print ("%s (%s)\n", snd_strerror (res),
1888 connector_get_msg_string (rx_msg));
1889 free_msg (rx_msg);
1890 return res;
1891 }
11871892 free_msg (rx_msg);
1188 if (id < 0)
1189 {
1190 errno = EEXIST;
1191 error_print ("%s\n", g_strerror (errno));
1192 }
1193
1194 data = (gshort *) sample->data;
1893
11951894 transferred = 0;
11961895 i = 0;
1197 g_mutex_lock (&transfer->mutex);
1198 active = (!transfer || transfer->active);
1199 g_mutex_unlock (&transfer->mutex);
1200 while (transferred < sample->len && active)
1201 {
1202 if (progress)
1203 {
1204 progress (transferred / (double) sample->len);
1205 }
1206
1207 tx_msg =
1208 connector_new_msg_write_file_blk (id, &data, sample->len,
1209 &transferred, i);
1896 if (control)
1897 {
1898 g_mutex_lock (&control->mutex);
1899 active = control->active;
1900 g_mutex_unlock (&control->mutex);
1901 }
1902 else
1903 {
1904 active = TRUE;
1905 }
1906
1907 while (transferred < input->len && active)
1908 {
1909 tx_msg = new_msg_write_blk (id, input, &transferred, i, control->data);
12101910 rx_msg = connector_tx_and_rx (connector, tx_msg);
12111911 if (!rx_msg)
12121912 {
1213 return -1;
1913 return -EIO;
12141914 }
12151915 //Response: x, x, x, x, 0xc2, [0 (error), 1 (success)]...
12161916 if (!connector_get_msg_status (rx_msg))
12191919 }
12201920 free_msg (rx_msg);
12211921 i++;
1222 g_mutex_lock (&transfer->mutex);
1223 active = (!transfer || transfer->active);
1224 g_mutex_unlock (&transfer->mutex);
1922
1923 if (control)
1924 {
1925 set_job_control_progress (control,
1926 transferred / (double) input->len);
1927 g_mutex_lock (&control->mutex);
1928 active = control->active;
1929 g_mutex_unlock (&control->mutex);
1930 }
12251931
12261932 usleep (REST_TIME);
12271933 }
12281934
1229 debug_print (2, "%zu frames sent\n", transferred);
1935 debug_print (2, "%d bytes sent\n", transferred);
12301936
12311937 if (active)
12321938 {
1233 if (progress)
1234 {
1235 progress (transferred / (double) sample->len);
1236 }
1237
1238 tx_msg = connector_new_msg_close_file_write (id, transferred);
1939 tx_msg = new_msg_close_write (id, transferred);
12391940 rx_msg = connector_tx_and_rx (connector, tx_msg);
12401941 if (!rx_msg)
12411942 {
1242 return -1;
1943 return -EIO;
12431944 }
12441945 //Response: x, x, x, x, 0xc1, [0 (error), 1 (success)]...
12451946 if (!connector_get_msg_status (rx_msg))
12491950 free_msg (rx_msg);
12501951 }
12511952
1252 return active ? transferred : -1;
1253 }
1254
1255 GArray *
1256 connector_download (struct connector *connector, const gchar * path,
1257 struct connector_sample_transfer *transfer,
1258 void (*progress) (gdouble))
1259 {
1953 return res;
1954 }
1955
1956 static gint
1957 connector_upload_sample_part (const gchar * path, GByteArray * sample,
1958 struct job_control *control, void *data)
1959 {
1960 return connector_upload_smplrw (path, sample, control, data,
1961 connector_new_msg_open_sample_write,
1962 connector_new_msg_write_sample_blk,
1963 connector_new_msg_close_sample_write);
1964 }
1965
1966 static gint
1967 connector_upload_sample (const gchar * path, GByteArray * output,
1968 struct job_control *control, void *data)
1969 {
1970 control->parts = 1;
1971 control->part = 0;
1972 return connector_upload_sample_part (path, output, control, data);
1973 }
1974
1975 static gint
1976 connector_upload_raw (const gchar * path, GByteArray * sample,
1977 struct job_control *control, void *data)
1978 {
1979 return connector_upload_smplrw (path, sample, control, data,
1980 connector_new_msg_open_raw_write,
1981 connector_new_msg_write_raw_blk,
1982 connector_new_msg_close_raw_write);
1983 }
1984
1985 static GByteArray *
1986 connector_new_msg_open_sample_read (const gchar * path)
1987 {
1988 return connector_new_msg_path (FS_SAMPLE_OPEN_FILE_READER_REQUEST,
1989 sizeof
1990 (FS_SAMPLE_OPEN_FILE_READER_REQUEST), path);
1991 }
1992
1993 static GByteArray *
1994 connector_new_msg_open_raw_read (const gchar * path)
1995 {
1996 return connector_new_msg_path (FS_RAW_OPEN_FILE_READER_REQUEST,
1997 sizeof
1998 (FS_RAW_OPEN_FILE_READER_REQUEST), path);
1999 }
2000
2001 static void
2002 connector_copy_sample_data (GByteArray * input, GByteArray * output)
2003 {
2004 gint i;
2005 gint16 v;
2006 gint16 *frame = (gint16 *) input->data;
2007
2008 for (i = 0; i < input->len; i += sizeof (gint16))
2009 {
2010 v = be16toh (*frame);
2011 g_byte_array_append (output, (guint8 *) & v, sizeof (gint16));
2012 frame++;
2013 }
2014 }
2015
2016 static void
2017 connector_copy_raw_data (GByteArray * input, GByteArray * output)
2018 {
2019 g_byte_array_append (output, input->data, input->len);
2020 }
2021
2022 static gint
2023 connector_download_smplrw (const gchar * path, GByteArray * output,
2024 struct job_control *control, void *data,
2025 connector_msg_path_func new_msg_open_read,
2026 guint read_offset,
2027 connector_msg_read_blk_func new_msg_read_blk,
2028 connector_msg_id_func new_msg_close_read,
2029 connector_copy_array copy_array)
2030 {
2031 struct connector *connector = data;
2032 struct sample_loop_data *sample_loop_data;
2033 struct elektron_sample_info *elektron_sample_info;
12602034 GByteArray *tx_msg;
12612035 GByteArray *rx_msg;
1262 GByteArray *data;
1263 gint id;
2036 GByteArray *array;
2037 guint32 id;
12642038 guint frames;
12652039 guint next_block_start;
12662040 guint req_size;
1267 int offset;
1268 int16_t v;
1269 int16_t *frame;
1270 int i;
2041 guint offset;
12712042 gboolean active;
1272 GArray *result;
1273 gchar *path_cp1252 =
1274 g_convert (path, -1, "CP1252", "UTF8", NULL, NULL, NULL);
1275
1276 if (!path_cp1252)
1277 {
1278 return NULL;
1279 }
1280
1281 tx_msg = connector_new_msg_open_file_read (path_cp1252);
1282 g_free (path_cp1252);
2043 gint res;
2044
2045 tx_msg = new_msg_open_read (path);
2046 if (!tx_msg)
2047 {
2048 return -EINVAL;
2049 }
2050
12832051 rx_msg = connector_tx_and_rx (connector, tx_msg);
12842052 if (!rx_msg)
12852053 {
1286 return NULL;
1287 }
1288 connector_get_sample_info_from_msg (rx_msg, &id, &frames);
2054 return -EIO;
2055 }
2056 res = connector_get_smplrw_info_from_msg (rx_msg, &id, &frames);
2057 if (res)
2058 {
2059 error_print ("%s (%s)\n", snd_strerror (res),
2060 connector_get_msg_string (rx_msg));
2061 free_msg (rx_msg);
2062 return res;
2063 }
12892064 free_msg (rx_msg);
1290 if (id < 0)
1291 {
1292 error_print ("File %s not found\n", path);
1293 return NULL;
1294 }
12952065
12962066 debug_print (2, "%d frames to download\n", frames);
12972067
1298 data = g_byte_array_new ();
1299
2068 if (control)
2069 {
2070 g_mutex_lock (&control->mutex);
2071 active = control->active;
2072 g_mutex_unlock (&control->mutex);
2073 }
2074 else
2075 {
2076 active = TRUE;
2077 }
2078
2079 array = g_byte_array_new ();
2080 res = 0;
13002081 next_block_start = 0;
1301 offset = 64;
1302 g_mutex_lock (&transfer->mutex);
1303 active = (!transfer || transfer->active);
1304 g_mutex_unlock (&transfer->mutex);
2082 offset = read_offset;
2083 control->data = NULL;
13052084 while (next_block_start < frames && active)
13062085 {
1307 if (progress)
1308 {
1309 progress (next_block_start / (double) frames);
1310 }
1311
13122086 req_size =
13132087 frames - next_block_start >
1314 TRANSF_BLOCK_SIZE_SAMPLE ? TRANSF_BLOCK_SIZE_SAMPLE : frames -
2088 DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : frames -
13152089 next_block_start;
1316 tx_msg =
1317 connector_new_msg_read_file_blk (id, next_block_start, req_size);
2090 tx_msg = new_msg_read_blk (id, next_block_start, req_size);
13182091 rx_msg = connector_tx_and_rx (connector, tx_msg);
13192092 if (!rx_msg)
13202093 {
1321 result = NULL;
2094 res = -EIO;
13222095 goto cleanup;
13232096 }
1324 g_byte_array_append (data, &rx_msg->data[22 + offset],
2097 g_byte_array_append (array, &rx_msg->data[FS_SAMPLES_PAD_RES + offset],
13252098 req_size - offset);
2099
2100 next_block_start += req_size;
2101 //Only in the first iteration. It has no effect for the raw filesystem (M:C) as offset is 0.
2102 if (offset)
2103 {
2104 offset = 0;
2105 elektron_sample_info =
2106 (struct elektron_sample_info *) &rx_msg->data[FS_SAMPLES_PAD_RES];
2107 sample_loop_data = malloc (sizeof (struct elektron_sample_info));
2108 sample_loop_data->start =
2109 be32toh (elektron_sample_info->loop_start);
2110 sample_loop_data->end = be32toh (elektron_sample_info->loop_end);
2111 control->data = sample_loop_data;
2112 debug_print (2, "Loop start at %d, loop end at %d\n",
2113 sample_loop_data->start, sample_loop_data->end);
2114 }
2115
13262116 free_msg (rx_msg);
13272117
1328 next_block_start += req_size;
1329 offset = 0;
1330 g_mutex_lock (&transfer->mutex);
1331 active = (!transfer || transfer->active);
1332 g_mutex_unlock (&transfer->mutex);
2118 if (control)
2119 {
2120 set_job_control_progress (control,
2121 next_block_start / (double) frames);
2122 g_mutex_lock (&control->mutex);
2123 active = control->active;
2124 g_mutex_unlock (&control->mutex);
2125 }
13332126
13342127 usleep (REST_TIME);
13352128 }
13382131
13392132 if (active)
13402133 {
1341 if (progress)
1342 {
1343 progress (next_block_start / (double) frames);
1344 }
1345
1346 result = g_array_new (FALSE, FALSE, sizeof (short));
1347 frame = (gshort *) data->data;
1348 for (i = 0; i < data->len; i += 2)
1349 {
1350 v = be16toh (*frame);
1351 g_array_append_val (result, v);
1352 frame++;
1353 }
2134 copy_array (array, output);
13542135 }
13552136 else
13562137 {
1357 result = NULL;
1358 }
1359
1360 tx_msg = connector_new_msg_close_file_read (id);
2138 res = -1;
2139 }
2140
2141 tx_msg = new_msg_close_read (id);
13612142 rx_msg = connector_tx_and_rx (connector, tx_msg);
13622143 if (!rx_msg)
13632144 {
1364 if (result)
1365 {
1366 g_array_free (result, TRUE);
1367 result = NULL;
1368 }
2145 res = -EIO;
13692146 goto cleanup;
13702147 }
13712148 //Response: x, x, x, x, 0xb1, 00 00 00 0a 00 01 65 de (sample id and received bytes)
13722149 free_msg (rx_msg);
13732150
13742151 cleanup:
1375 free_msg (data);
1376 return result;
1377 }
1378
1379 gint
1380 connector_create_dir (struct connector *connector, const gchar * path)
1381 {
1382 GByteArray *tx_msg;
1383 GByteArray *rx_msg;
1384 gint res;
1385 gchar *path_cp1252 =
1386 g_convert (path, -1, "CP1252", "UTF8", NULL, NULL, NULL);
1387
1388 if (!path_cp1252)
1389 {
1390 errno = EINVAL;
1391 return -1;
1392 }
1393
1394 tx_msg = connector_new_msg_new_dir (path_cp1252);
1395 g_free (path_cp1252);
1396 rx_msg = connector_tx_and_rx (connector, tx_msg);
1397 if (!rx_msg)
1398 {
1399 return -1;
1400 }
1401 //Response: x, x, x, x, 0x91, [0 (error), 1 (success)]...
1402 if (connector_get_msg_status (rx_msg))
1403 {
1404 res = 0;
1405 }
1406 else
1407 {
1408 res = -1;
1409 errno = EEXIST;
1410 error_print ("%s\n", g_strerror (errno));
1411 }
1412 free_msg (rx_msg);
1413
2152 free_msg (array);
2153 if (res)
2154 {
2155 g_free (control->data);
2156 }
14142157 return res;
2158 }
2159
2160 static gint
2161 connector_download_sample_part (const gchar * path, GByteArray * output,
2162 struct job_control *control, void *data)
2163 {
2164 return connector_download_smplrw (path, output, control, data,
2165 connector_new_msg_open_sample_read,
2166 sizeof
2167 (struct elektron_sample_info),
2168 connector_new_msg_read_sample_blk,
2169 connector_new_msg_close_sample_read,
2170 connector_copy_sample_data);
2171 }
2172
2173 static gint
2174 connector_download_sample (const gchar * path, GByteArray * output,
2175 struct job_control *control, void *data)
2176 {
2177 control->parts = 1;
2178 control->part = 0;
2179 return connector_download_sample_part (path, output, control, data);
2180 }
2181
2182 static gint
2183 connector_download_raw (const gchar * path, GByteArray * output,
2184 struct job_control *control, void *data)
2185 {
2186 gint ret;
2187 gchar *path_with_ext = connector_add_ext_to_mc_snd (path);
2188 ret = connector_download_smplrw (path_with_ext, output, control, data,
2189 connector_new_msg_open_raw_read,
2190 0,
2191 connector_new_msg_read_raw_blk,
2192 connector_new_msg_close_raw_read,
2193 connector_copy_raw_data);
2194 g_free (path_with_ext);
2195 return ret;
2196 }
2197
2198 static gint
2199 connector_create_samples_dir (const gchar * path, void *data)
2200 {
2201 struct connector *connector = data;
2202 return connector_path_common (connector, path, FS_SAMPLE_CREATE_DIR_REQUEST,
2203 sizeof (FS_SAMPLE_CREATE_DIR_REQUEST));
2204 }
2205
2206 static gint
2207 connector_create_raw_dir (const gchar * path, void *data)
2208 {
2209 struct connector *connector = data;
2210 return connector_path_common (connector, path, FS_RAW_CREATE_DIR_REQUEST,
2211 sizeof (FS_RAW_CREATE_DIR_REQUEST));
14152212 }
14162213
14172214 static GByteArray *
14182215 connector_new_msg_upgrade_os_start (guint size)
14192216 {
1420 GByteArray *msg = connector_new_msg_data (INQ_OS_UPGRADE_START,
1421 sizeof (INQ_OS_UPGRADE_START));
1422
1423 memcpy (&msg->data[5], &size, sizeof (uint32_t));
2217 GByteArray *msg = connector_new_msg (OS_UPGRADE_START_REQUEST,
2218 sizeof (OS_UPGRADE_START_REQUEST));
2219
2220 memcpy (&msg->data[5], &size, sizeof (guint32));
14242221
14252222 return msg;
14262223 }
14282225 static GByteArray *
14292226 connector_new_msg_upgrade_os_write (GByteArray * os_data, gint * offset)
14302227 {
1431 GByteArray *msg = connector_new_msg_data (INQ_OS_UPGRADE_WRITE,
1432 sizeof (INQ_OS_UPGRADE_WRITE));
2228 GByteArray *msg = connector_new_msg (OS_UPGRADE_WRITE_RESPONSE,
2229 sizeof (OS_UPGRADE_WRITE_RESPONSE));
14332230 guint len;
1434 uint32_t crc;
1435 uint32_t aux32;
1436
1437 if (*offset + TRANSF_BLOCK_SIZE_OS < os_data->len)
1438 {
1439 len = TRANSF_BLOCK_SIZE_OS;
2231 guint32 crc;
2232 guint32 aux32;
2233
2234 if (*offset + OS_TRANSF_BLOCK_BYTES < os_data->len)
2235 {
2236 len = OS_TRANSF_BLOCK_BYTES;
14402237 }
14412238 else
14422239 {
14482245 debug_print (2, "CRC: %0x\n", crc);
14492246
14502247 aux32 = htobe32 (crc);
1451 memcpy (&msg->data[5], &aux32, sizeof (uint32_t));
2248 memcpy (&msg->data[5], &aux32, sizeof (guint32));
14522249 aux32 = htobe32 (len);
1453 memcpy (&msg->data[9], &aux32, sizeof (uint32_t));
2250 memcpy (&msg->data[9], &aux32, sizeof (guint32));
14542251 aux32 = htobe32 (*offset);
1455 memcpy (&msg->data[13], &aux32, sizeof (uint32_t));
2252 memcpy (&msg->data[13], &aux32, sizeof (guint32));
14562253
14572254 g_byte_array_append (msg, &os_data->data[*offset], len);
14582255
14622259 }
14632260
14642261 gint
1465 connector_upgrade_os (struct connector *connector, GByteArray * data,
2262 connector_upgrade_os (struct connector *connector,
14662263 struct connector_sysex_transfer *transfer)
14672264 {
14682265 GByteArray *tx_msg;
14732270
14742271 transfer->status = SENDING;
14752272
1476 tx_msg = connector_new_msg_upgrade_os_start (data->len);
2273 tx_msg = connector_new_msg_upgrade_os_start (transfer->raw->len);
14772274 rx_msg = connector_tx_and_rx (connector, tx_msg);
14782275
14792276 if (!rx_msg)
14802277 {
1481 res = -1;
2278 res = -EIO;
14822279 goto end;
14832280 }
14842281 //Response: x, x, x, x, 0xd1, [0 (ok), 1 (error)]...
14852282 op = connector_get_msg_status (rx_msg);
14862283 if (op)
14872284 {
1488 res = -1;
1489 errno = EIO;
1490 error_print ("%s (%s)\n", g_strerror (errno),
2285 res = -EIO;
2286 error_print ("%s (%s)\n", snd_strerror (res),
14912287 connector_get_msg_string (rx_msg));
14922288 free_msg (rx_msg);
14932289 goto end;
14962292 free_msg (rx_msg);
14972293
14982294 offset = 0;
1499 while (offset < data->len && transfer->active)
1500 {
1501 tx_msg = connector_new_msg_upgrade_os_write (data, &offset);
2295 while (offset < transfer->raw->len && transfer->active)
2296 {
2297 tx_msg = connector_new_msg_upgrade_os_write (transfer->raw, &offset);
15022298 rx_msg = connector_tx_and_rx (connector, tx_msg);
15032299
15042300 if (!rx_msg)
15052301 {
1506 res = -1;
2302 res = -EIO;
15072303 break;
15082304 }
15092305 //Response: x, x, x, x, 0xd1, int32, [0..3]...
15142310 }
15152311 else if (op > 1)
15162312 {
1517 res = -1;
1518 errno = EIO;
1519 error_print ("%s (%s)\n", g_strerror (errno),
2313 res = -EIO;
2314 error_print ("%s (%s)\n", snd_strerror (res),
15202315 connector_get_msg_string (rx_msg));
15212316 free_msg (rx_msg);
15222317 break;
15462341 if (err)
15472342 {
15482343 error_print ("Error while closing MIDI port: %s\n",
1549 g_strerror (errno));
2344 snd_strerror (err));
15502345 }
15512346 connector->inputp = NULL;
15522347 }
15572352 if (err)
15582353 {
15592354 error_print ("Error while closing MIDI port: %s\n",
1560 g_strerror (errno));
2355 snd_strerror (err));
15612356 }
15622357 connector->outputp = NULL;
15632358 }
15652360 if (connector->device_name)
15662361 {
15672362 free (connector->device_name);
2363 free (connector->fw_version);
2364 free (connector->alias);
15682365 connector->device_name = NULL;
15692366 }
15702367
15792376 free (connector->pfds);
15802377 connector->pfds = NULL;
15812378 }
2379
2380 if (connector->dir_cache)
2381 {
2382 g_hash_table_destroy (connector->dir_cache);
2383 connector->dir_cache = NULL;
2384 }
15822385 }
15832386
15842387 gint
1585 connector_statfs (struct connector *connector, enum connector_fs_type type,
1586 struct connector_statfs *statfs)
2388 connector_get_storage_stats (struct connector *connector,
2389 enum connector_storage type,
2390 struct connector_storage_stats *statfs)
15872391 {
15882392 GByteArray *tx_msg;
15892393 GByteArray *rx_msg;
15902394 gint8 op;
1591 uint64_t *data;
2395 guint64 *data;
2396 int index;
15922397 gint res = 0;
15932398
1594 tx_msg = connector_new_msg_uint8 (INQ_STORAGE_INFO,
1595 sizeof (INQ_STORAGE_INFO), type);
2399 tx_msg = connector_new_msg_uint8 (STORAGEINFO_REQUEST,
2400 sizeof (STORAGEINFO_REQUEST), type);
15962401 rx_msg = connector_tx_and_rx (connector, tx_msg);
1597
15982402 if (!rx_msg)
15992403 {
1600 return -1;
2404 return -EIO;
16012405 }
16022406
16032407 op = connector_get_msg_status (rx_msg);
16042408 if (!op)
16052409 {
1606 errno = EIO;
1607 error_print ("%s (%s)\n", g_strerror (errno),
2410 error_print ("%s (%s)\n", snd_strerror (-EIO),
16082411 connector_get_msg_string (rx_msg));
16092412 free_msg (rx_msg);
1610 return -1;
1611 }
1612
1613 statfs->name = FS_TYPE_NAMES[type];
1614 data = (uint64_t *) & rx_msg->data[6];
2413 return -EIO;
2414 }
2415
2416 index = 0;
2417 for (int i = 0, storage = STORAGE_PLUS_DRIVE; storage <= STORAGE_RAM;
2418 i++, storage <<= 1)
2419 {
2420 if (storage == type)
2421 {
2422 index = i;
2423 }
2424 }
2425
2426 statfs->name = FS_TYPE_NAMES[index];
2427 data = (guint64 *) & rx_msg->data[6];
16152428 statfs->bfree = be64toh (*data);
1616 data = (uint64_t *) & rx_msg->data[14];
2429 data = (guint64 *) & rx_msg->data[14];
16172430 statfs->bsize = be64toh (*data);
16182431
16192432 free_msg (rx_msg);
16212434 return res;
16222435 }
16232436
1624 float
1625 connector_statfs_use_percent (struct connector_statfs *statfs)
2437 gdouble
2438 connector_get_storage_stats_percent (struct connector_storage_stats *statfs)
16262439 {
16272440 return (statfs->bsize - statfs->bfree) * 100.0 / statfs->bsize;
16282441 }
16412454 return CONNECTOR_DEVICE_DESCS[i];
16422455 }
16432456 }
1644 return &NULL_DEVICE_DESC;
2457 return NULL;
16452458 }
16462459
16472460 gint
16492462 {
16502463 int err;
16512464 GByteArray *tx_msg;
1652 GByteArray *rx_msg_device;
1653 GByteArray *rx_msg_fw_ver;
1654 GByteArray *rx_msg_uid;
2465 GByteArray *rx_msg;
16552466 snd_rawmidi_params_t *params;
16562467 gchar name[32];
16572468 sprintf (name, "hw:%d", card);
16612472 connector->buffer = NULL;
16622473 connector->rx_len = 0;
16632474 connector->pfds = NULL;
2475 connector->dir_cache = NULL;
16642476 if (card < 0)
16652477 {
16662478 debug_print (1, "Invalid card\n");
16732485 snd_rawmidi_open (&connector->inputp, &connector->outputp,
16742486 name, SND_RAWMIDI_NONBLOCK | SND_RAWMIDI_SYNC)) < 0)
16752487 {
1676 error_print ("Error while opening MIDI port: %s\n", g_strerror (errno));
2488 error_print ("Error while opening MIDI port: %s\n", g_strerror (err));
16772489 goto cleanup;
16782490 }
16792491
17422554 goto cleanup_params;
17432555 }
17442556
1745 tx_msg = connector_new_msg_data (INQ_DEVICE, sizeof (INQ_DEVICE));
1746 rx_msg_device = connector_tx_and_rx (connector, tx_msg);
1747 if (!rx_msg_device)
1748 {
1749 err = -errno;
1750 goto cleanup;
1751 }
1752
1753 tx_msg = connector_new_msg_data (INQ_VERSION, sizeof (INQ_VERSION));
1754 rx_msg_fw_ver = connector_tx_and_rx (connector, tx_msg);
1755 if (!rx_msg_fw_ver)
1756 {
1757 err = -errno;
1758 goto cleanup_device;
1759 }
2557 tx_msg = connector_new_msg (PING_REQUEST, sizeof (PING_REQUEST));
2558 rx_msg = connector_tx_and_rx (connector, tx_msg);
2559 if (!rx_msg)
2560 {
2561 err = -EIO;
2562 goto cleanup_params;
2563 }
2564 connector->alias = strdup ((gchar *) & rx_msg->data[7 + rx_msg->data[6]]);
2565 connector->device_desc = connector_get_device_desc (rx_msg->data[5]);
2566 free_msg (rx_msg);
2567 if (!connector->device_desc)
2568 {
2569 err = -ENODEV;
2570 goto cleanup_params;
2571 }
2572
2573 tx_msg =
2574 connector_new_msg (SOFTWARE_VERSION_REQUEST,
2575 sizeof (SOFTWARE_VERSION_REQUEST));
2576 rx_msg = connector_tx_and_rx (connector, tx_msg);
2577 if (!rx_msg)
2578 {
2579 err = -EIO;
2580 goto cleanup_params;
2581 }
2582 connector->fw_version = strdup ((gchar *) & rx_msg->data[10]);
2583 free_msg (rx_msg);
17602584
17612585 if (debug_level > 1)
17622586 {
1763 tx_msg = connector_new_msg_data (INQ_UID, sizeof (INQ_UID));
1764 rx_msg_uid = connector_tx_and_rx (connector, tx_msg);
1765 if (rx_msg_uid)
1766 {
1767 debug_print (1, "UID: %x\n", *((guint32 *) & rx_msg_uid->data[5]));
1768 free_msg (rx_msg_uid);
1769 }
1770 }
1771
1772 connector->device_desc = connector_get_device_desc (rx_msg_device->data[5]);
2587 tx_msg =
2588 connector_new_msg (DEVICEUID_REQUEST, sizeof (DEVICEUID_REQUEST));
2589 rx_msg = connector_tx_and_rx (connector, tx_msg);
2590 if (rx_msg)
2591 {
2592 debug_print (1, "UID: %x\n", *((guint32 *) & rx_msg->data[5]));
2593 free_msg (rx_msg);
2594 }
2595 }
17732596
17742597 snprintf (connector->device_name, LABEL_MAX, "%s %s (%s)",
1775 connector->device_desc->model,
1776 &rx_msg_fw_ver->data[10],
1777 &rx_msg_device->data[7 + rx_msg_device->data[6]]);
2598 connector->device_desc->name,
2599 connector->fw_version, connector->alias);
17782600 debug_print (1, "Connected to %s\n", connector->device_name);
17792601 err = 0;
1780 free_msg (rx_msg_fw_ver);
1781 cleanup_device:
1782 free_msg (rx_msg_device);
2602
17832603 cleanup_params:
17842604 snd_rawmidi_params_free (params);
17852605 cleanup:
18892709 return;
18902710 }
18912711 device = -1;
1892 while (((err = snd_ctl_rawmidi_next_device (ctl, &device)) == 0)
1893 && (device >= 0))
2712 while (!(err = snd_ctl_rawmidi_next_device (ctl, &device)) && device >= 0)
18942713 {
18952714 connector_system_device =
18962715 connector_get_system_device (ctl, card, device);
19152734 g_array_new (FALSE, FALSE, sizeof (struct connector_system_device));
19162735
19172736 card = -1;
1918 while (((err = snd_card_next (&card)) == 0) && (card >= 0))
2737 while (!(err = snd_card_next (&card)) && card >= 0)
19192738 {
19202739 connector_fill_card_elektron_devices (card, devices);
19212740 }
19262745
19272746 return devices;
19282747 }
2748
2749 static guint
2750 connector_next_data_entry (struct item_iterator *iter)
2751 {
2752 gchar *name_cp1252;
2753 guint32 *data32;
2754 guint16 *data16;
2755 guint8 type;
2756 guint8 has_children;
2757 struct connector_iterator_data *data = iter->data;
2758
2759 if (iter->item.name != NULL)
2760 {
2761 g_free (iter->item.name);
2762 }
2763
2764 if (data->pos == data->msg->len)
2765 {
2766 iter->item.name = NULL;
2767 return -ENOENT;
2768 }
2769
2770 name_cp1252 = (gchar *) & data->msg->data[data->pos];
2771 iter->item.name = connector_get_utf8 (name_cp1252);
2772 data->pos += strlen (name_cp1252) + 1;
2773 has_children = data->msg->data[data->pos];
2774 data->pos++;
2775 type = data->msg->data[data->pos];
2776 data->pos++;
2777
2778 switch (type)
2779 {
2780 case 1:
2781 iter->item.type = ELEKTROID_DIR;
2782 data->pos += sizeof (guint32); // child entries
2783 iter->item.size = 0;
2784 iter->item.index = -1;
2785 data->operations = 0;
2786 data->has_valid_data = 0;
2787 data->has_metadata = 0;
2788 break;
2789 case 2:
2790 iter->item.type = has_children ? ELEKTROID_DIR : ELEKTROID_FILE;
2791
2792 data32 = (guint32 *) & data->msg->data[data->pos];
2793 iter->item.index = be32toh (*data32); //index
2794 data->pos += sizeof (gint32);
2795
2796 data32 = (guint32 *) & data->msg->data[data->pos];
2797 iter->item.size = be32toh (*data32);
2798 data->pos += sizeof (guint32);
2799
2800 data16 = (guint16 *) & data->msg->data[data->pos];
2801 data->operations = be16toh (*data16);
2802 data->pos += sizeof (guint16);
2803
2804 data->has_valid_data = data->msg->data[data->pos];
2805 data->pos++;
2806
2807 data->has_metadata = data->msg->data[data->pos];
2808 data->pos++;
2809
2810 break;
2811 default:
2812 error_print ("Unrecognized data entry: %d\n", iter->item.type);
2813 break;
2814 }
2815
2816 return 0;
2817 }
2818
2819 static gchar *
2820 connector_add_prefix_to_path (const gchar * dir, const gchar * prefix)
2821 {
2822 gchar *full = malloc (PATH_MAX);
2823
2824 if (prefix)
2825 {
2826 snprintf (full, PATH_MAX, "%s%s", prefix, dir);
2827 }
2828 else
2829 {
2830 strcpy (full, dir);
2831 }
2832
2833 return full;
2834 }
2835
2836 static gint
2837 connector_read_data_dir_prefix (struct item_iterator *iter, const gchar * dir,
2838 void *data, const char *prefix)
2839 {
2840 int res;
2841 GByteArray *tx_msg;
2842 GByteArray *rx_msg;
2843 struct connector *connector = data;
2844 gchar *dir_w_prefix = connector_add_prefix_to_path (dir, prefix);
2845
2846 tx_msg = connector_new_msg_list (dir_w_prefix, 0, 0, 1);
2847 g_free (dir_w_prefix);
2848 if (!tx_msg)
2849 {
2850 return -EINVAL;
2851 }
2852
2853 rx_msg = connector_tx_and_rx (connector, tx_msg);
2854 if (!rx_msg)
2855 {
2856 return -EIO;
2857 }
2858
2859 res = connector_get_msg_status (rx_msg);
2860 if (!res)
2861 {
2862 free_msg (rx_msg);
2863 return -ENOTDIR;
2864 }
2865
2866 return connector_init_iterator (iter, rx_msg, connector_next_data_entry,
2867 FS_DATA_ALL, FALSE);
2868 }
2869
2870 static gint
2871 connector_read_data_dir_any (struct item_iterator *iter, const gchar * dir,
2872 void *data)
2873 {
2874 return connector_read_data_dir_prefix (iter, dir, data, NULL);
2875 }
2876
2877 static gint
2878 connector_read_data_dir_prj (struct item_iterator *iter, const gchar * dir,
2879 void *data)
2880 {
2881 return connector_read_data_dir_prefix (iter, dir, data, FS_DATA_PRJ_PREFIX);
2882 }
2883
2884 static gint
2885 connector_read_data_dir_snd (struct item_iterator *iter, const gchar * dir,
2886 void *data)
2887 {
2888 return connector_read_data_dir_prefix (iter, dir, data, FS_DATA_SND_PREFIX);
2889 }
2890
2891 static gint
2892 connector_dst_src_data_prefix_common (const gchar * src, const gchar * dst,
2893 void *data, const char *prefix,
2894 const guint8 * op_data, guint len)
2895 {
2896 gint res;
2897 struct connector *connector = data;
2898 char *src_w_prefix = connector_add_prefix_to_path (src, prefix);
2899 char *dst_w_prefix = connector_add_prefix_to_path (dst, prefix);
2900
2901 res = connector_src_dst_common (connector, src_w_prefix, dst_w_prefix,
2902 op_data, len);
2903 g_free (src_w_prefix);
2904 g_free (dst_w_prefix);
2905
2906 return res;
2907 }
2908
2909 static gint
2910 connector_move_data_item_prefix (const gchar * src, const gchar * dst,
2911 void *data, const char *prefix)
2912 {
2913 return connector_dst_src_data_prefix_common (src, dst, data, prefix,
2914 DATA_MOVE_REQUEST,
2915 sizeof (DATA_MOVE_REQUEST));
2916 }
2917
2918 static gint
2919 connector_move_data_item_any (const gchar * src, const gchar * dst,
2920 void *data)
2921 {
2922 return connector_move_data_item_prefix (src, dst, data, NULL);
2923 }
2924
2925 static gint
2926 connector_move_data_item_prj (const gchar * src, const gchar * dst,
2927 void *data)
2928 {
2929 return connector_move_data_item_prefix (src, dst, data, FS_DATA_PRJ_PREFIX);
2930 }
2931
2932 static gint
2933 connector_move_data_item_snd (const gchar * src, const gchar * dst,
2934 void *data)
2935 {
2936 return connector_move_data_item_prefix (src, dst, data, FS_DATA_SND_PREFIX);
2937 }
2938
2939 static gint
2940 connector_copy_data_item_prefix (const gchar * src, const gchar * dst,
2941 void *data, const gchar * prefix)
2942 {
2943 return connector_dst_src_data_prefix_common (src, dst, data, prefix,
2944 DATA_COPY_REQUEST,
2945 sizeof (DATA_COPY_REQUEST));
2946 }
2947
2948 static gint
2949 connector_copy_data_item_any (const gchar * src, const gchar * dst,
2950 void *data)
2951 {
2952 return connector_copy_data_item_prefix (src, dst, data, NULL);
2953 }
2954
2955 static gint
2956 connector_copy_data_item_prj (const gchar * src, const gchar * dst,
2957 void *data)
2958 {
2959 return connector_copy_data_item_prefix (src, dst, data, FS_DATA_PRJ_PREFIX);
2960 }
2961
2962 static gint
2963 connector_copy_data_item_snd (const gchar * src, const gchar * dst,
2964 void *data)
2965 {
2966 return connector_copy_data_item_prefix (src, dst, data, FS_DATA_SND_PREFIX);
2967 }
2968
2969 static gint
2970 connector_path_data_prefix_common (const gchar * path,
2971 void *data, const char *prefix,
2972 const guint8 * op_data, guint len)
2973 {
2974 gint res;
2975 struct connector *connector = data;
2976 char *path_w_prefix = connector_add_prefix_to_path (path, prefix);
2977
2978 res = connector_path_common (connector, path_w_prefix, op_data, len);
2979 g_free (path_w_prefix);
2980
2981 return res;
2982 }
2983
2984 static gint
2985 connector_clear_data_item_prefix (const gchar * path, void *data,
2986 const gchar * prefix)
2987 {
2988 return connector_path_data_prefix_common (path, data, prefix,
2989 DATA_CLEAR_REQUEST,
2990 sizeof (DATA_CLEAR_REQUEST));
2991 }
2992
2993 static gint
2994 connector_clear_data_item_any (const gchar * path, void *data)
2995 {
2996 return connector_clear_data_item_prefix (path, data, NULL);
2997 }
2998
2999 static gint
3000 connector_clear_data_item_prj (const gchar * path, void *data)
3001 {
3002 return connector_clear_data_item_prefix (path, data, FS_DATA_PRJ_PREFIX);
3003 }
3004
3005 static gint
3006 connector_clear_data_item_snd (const gchar * path, void *data)
3007 {
3008 return connector_clear_data_item_prefix (path, data, FS_DATA_SND_PREFIX);
3009 }
3010
3011 static gint
3012 connector_swap_data_item_prefix (const gchar * src, const gchar * dst,
3013 void *data, const gchar * prefix)
3014 {
3015 return connector_dst_src_data_prefix_common (src, dst, data, prefix,
3016 DATA_SWAP_REQUEST,
3017 sizeof (DATA_SWAP_REQUEST));
3018 }
3019
3020 static gint
3021 connector_swap_data_item_any (const gchar * src, const gchar * dst,
3022 void *data)
3023 {
3024 return connector_swap_data_item_prefix (src, dst, data, NULL);
3025 }
3026
3027 static gint
3028 connector_swap_data_item_prj (const gchar * src, const gchar * dst,
3029 void *data)
3030 {
3031 return connector_swap_data_item_prefix (src, dst, data, FS_DATA_PRJ_PREFIX);
3032 }
3033
3034 static gint
3035 connector_swap_data_item_snd (const gchar * src, const gchar * dst,
3036 void *data)
3037 {
3038 return connector_swap_data_item_prefix (src, dst, data, FS_DATA_SND_PREFIX);
3039 }
3040
3041 static gint
3042 connector_open_datum (struct connector *connector, const gchar * path,
3043 guint32 * jid, gint mode, guint32 size)
3044 {
3045 guint32 *data32;
3046 guint32 sizebe;
3047 guint32 chunk_size;
3048 guint8 compression;
3049 GByteArray *rx_msg;
3050 GByteArray *tx_msg;
3051 const guint8 *data;
3052 guint len;
3053 gchar *path_cp1252;
3054 gint res = 0;
3055
3056 if (mode == O_RDONLY)
3057 {
3058 data = DATA_READ_OPEN_REQUEST;
3059 len = sizeof (DATA_READ_OPEN_REQUEST);
3060 }
3061 else if (mode == O_WRONLY)
3062 {
3063 data = DATA_WRITE_OPEN_REQUEST;
3064 len = sizeof (DATA_WRITE_OPEN_REQUEST);
3065 }
3066 else
3067 {
3068 return -EINVAL;
3069 }
3070
3071 tx_msg = connector_new_msg (data, len);
3072 if (!tx_msg)
3073 {
3074 return -ENOMEM;
3075 }
3076
3077 path_cp1252 = connector_get_cp1252 (path);
3078
3079 if (mode == O_RDONLY)
3080 {
3081 g_byte_array_append (tx_msg, (guint8 *) path_cp1252,
3082 strlen (path_cp1252) + 1);
3083 chunk_size = htobe32 (DATA_TRANSF_BLOCK_BYTES);
3084 g_byte_array_append (tx_msg, (guint8 *) & chunk_size, sizeof (guint32));
3085 compression = 1;
3086 g_byte_array_append (tx_msg, &compression, sizeof (guint8));
3087 }
3088
3089 if (mode == O_WRONLY)
3090 {
3091 sizebe = htobe32 (size);
3092 g_byte_array_append (tx_msg, (guint8 *) & sizebe, sizeof (guint32));
3093 g_byte_array_append (tx_msg, (guint8 *) path_cp1252,
3094 strlen (path_cp1252) + 1);
3095 }
3096
3097 rx_msg = connector_tx_and_rx (connector, tx_msg);
3098 if (!rx_msg)
3099 {
3100 res = -EIO;
3101 goto cleanup;
3102 }
3103
3104 if (!connector_get_msg_status (rx_msg))
3105 {
3106 res = -EPERM;
3107 error_print ("%s (%s)\n", snd_strerror (res),
3108 connector_get_msg_string (rx_msg));
3109 free_msg (rx_msg);
3110 goto cleanup;
3111 }
3112
3113 data32 = (guint32 *) & rx_msg->data[6];
3114 *jid = be32toh (*data32);
3115
3116 if (mode == O_RDONLY)
3117 {
3118 data32 = (guint32 *) & rx_msg->data[10];
3119 chunk_size = be32toh (*data32);
3120
3121 compression = rx_msg->data[14];
3122
3123 debug_print (1,
3124 "Open datum info: job id: %d; chunk size: %d; compression: %d\n",
3125 *jid, chunk_size, compression);
3126 }
3127
3128 if (mode == O_WRONLY)
3129 {
3130 debug_print (1, "Open datum info: job id: %d\n", *jid);
3131 }
3132
3133 free_msg (rx_msg);
3134
3135 cleanup:
3136 g_free (path_cp1252);
3137 return res;
3138 }
3139
3140 static gint
3141 connector_close_datum (struct connector *connector,
3142 guint32 jid, gint mode, guint32 wsize)
3143 {
3144 guint32 jidbe;
3145 guint32 wsizebe;
3146 guint32 r_jid;
3147 guint32 asize;
3148 guint32 *data32;
3149 GByteArray *rx_msg;
3150 GByteArray *tx_msg;
3151 const guint8 *data;
3152 guint len;
3153
3154 if (mode == O_RDONLY)
3155 {
3156 data = DATA_READ_CLOSE_REQUEST;
3157 len = sizeof (DATA_READ_CLOSE_REQUEST);
3158 }
3159 else if (mode == O_WRONLY)
3160 {
3161 data = DATA_WRITE_CLOSE_REQUEST;
3162 len = sizeof (DATA_WRITE_CLOSE_REQUEST);
3163 }
3164 else
3165 {
3166 return -EINVAL;
3167 }
3168
3169 tx_msg = connector_new_msg (data, len);
3170 if (!tx_msg)
3171 {
3172 return -ENOMEM;
3173 }
3174
3175 jidbe = htobe32 (jid);
3176 g_byte_array_append (tx_msg, (guchar *) & jidbe, sizeof (guint32));
3177
3178 if (mode == O_WRONLY)
3179 {
3180 wsizebe = htobe32 (wsize);
3181 g_byte_array_append (tx_msg, (guchar *) & wsizebe, sizeof (guint32));
3182 }
3183
3184 rx_msg = connector_tx_and_rx (connector, tx_msg);
3185 if (!rx_msg)
3186 {
3187 return -EIO;
3188 }
3189
3190 if (!connector_get_msg_status (rx_msg))
3191 {
3192 error_print ("%s (%s)\n", snd_strerror (-EPERM),
3193 connector_get_msg_string (rx_msg));
3194 free_msg (rx_msg);
3195 return -EPERM;
3196 }
3197
3198 data32 = (guint32 *) & rx_msg->data[6];
3199 r_jid = be32toh (*data32);
3200
3201 data32 = (guint32 *) & rx_msg->data[10];
3202 asize = be32toh (*data32);
3203
3204 debug_print (1, "Close datum info: job id: %d; size: %d\n", r_jid, asize);
3205
3206 free_msg (rx_msg);
3207
3208 if (mode == O_WRONLY && asize != wsize)
3209 {
3210 error_print
3211 ("Actual download bytes (%d) differs from expected ones (%d)\n",
3212 asize, wsize);
3213 return -EINVAL;
3214 }
3215
3216 return 0;
3217 }
3218
3219 static gint
3220 connector_download_data_prefix (const gchar * path, GByteArray * output,
3221 struct job_control *control, void *data,
3222 const gchar * prefix)
3223 {
3224 gint res;
3225 guint32 seq;
3226 guint32 seqbe;
3227 guint32 jid;
3228 guint32 r_jid;
3229 guint32 r_seq;
3230 guint32 status;
3231 guint8 last;
3232 guint32 hash;
3233 guint32 *data32;
3234 guint32 jidbe;
3235 guint32 data_size;
3236 gboolean active;
3237 GByteArray *rx_msg;
3238 GByteArray *tx_msg;
3239 gchar *path_w_prefix = connector_add_prefix_to_path (path, prefix);
3240 struct connector *connector = data;
3241
3242 res = connector_open_datum (connector, path_w_prefix, &jid, O_RDONLY, 0);
3243 g_free (path_w_prefix);
3244 if (res)
3245 {
3246 return -EIO;
3247 }
3248
3249 usleep (REST_TIME);
3250
3251 jidbe = htobe32 (jid);
3252
3253 res = 0;
3254 seq = 0;
3255 last = 0;
3256 control->data = NULL;
3257 if (control)
3258 {
3259 g_mutex_lock (&control->mutex);
3260 active = control->active;
3261 g_mutex_unlock (&control->mutex);
3262 }
3263 else
3264 {
3265 active = TRUE;
3266 }
3267 while (!last && active)
3268 {
3269 tx_msg =
3270 connector_new_msg (DATA_READ_PARTIAL_REQUEST,
3271 sizeof (DATA_READ_PARTIAL_REQUEST));
3272 g_byte_array_append (tx_msg, (guint8 *) & jidbe, sizeof (guint32));
3273 seqbe = htobe32 (seq);
3274 g_byte_array_append (tx_msg, (guint8 *) & seqbe, sizeof (guint32));
3275 rx_msg = connector_tx_and_rx (connector, tx_msg);
3276 if (!rx_msg)
3277 {
3278 res = -EIO;
3279 break;
3280 }
3281
3282 if (!connector_get_msg_status (rx_msg))
3283 {
3284 res = -EPERM;
3285 error_print ("%s (%s)\n", snd_strerror (res),
3286 connector_get_msg_string (rx_msg));
3287 free_msg (rx_msg);
3288 break;
3289 }
3290
3291 data32 = (guint32 *) & rx_msg->data[6];
3292 r_jid = be32toh (*data32);
3293
3294 data32 = (guint32 *) & rx_msg->data[10];
3295 r_seq = be32toh (*data32);
3296
3297 data32 = (guint32 *) & rx_msg->data[14];
3298 status = be32toh (*data32);
3299
3300 last = rx_msg->data[18];
3301
3302 data32 = (guint32 *) & rx_msg->data[19];
3303 hash = be32toh (*data32);
3304
3305 data32 = (guint32 *) & rx_msg->data[23];
3306 data_size = be32toh (*data32);
3307
3308 if (data_size)
3309 {
3310 debug_print (1,
3311 "Read datum info: job id: %d; last: %d; seq: %d; status: %d; hash: 0x%08x\n",
3312 r_jid, last, r_seq, status, hash);
3313
3314 g_byte_array_append (output, (guint8 *) & rx_msg->data[27],
3315 data_size);
3316 }
3317 else
3318 {
3319 // Sometimes, the first message returns 0 data size and the rest of the parameters are not initialized.
3320 debug_print (1,
3321 "Read datum info: job id: %d; last: %d, hash: 0x%08x\n",
3322 r_jid, last, hash);
3323 status = 0;
3324 }
3325
3326 free_msg (rx_msg);
3327 seq++;
3328
3329 if (control)
3330 {
3331 set_job_control_progress (control, status / 1000.0);
3332 g_mutex_lock (&control->mutex);
3333 active = control->active;
3334 g_mutex_unlock (&control->mutex);
3335 }
3336
3337 usleep (REST_TIME);
3338 }
3339
3340 return connector_close_datum (connector, jid, O_RDONLY, 0);
3341 }
3342
3343 static gint
3344 connector_download_data_any (const gchar * path, GByteArray * output,
3345 struct job_control *control, void *data)
3346 {
3347 control->parts = 1;
3348 control->part = 0;
3349 return connector_download_data_prefix (path, output, control, data, NULL);
3350 }
3351
3352 static gint
3353 connector_download_data_prj (const gchar * path, GByteArray * output,
3354 struct job_control *control, void *data)
3355 {
3356 return connector_download_data_prefix (path, output, control, data,
3357 FS_DATA_PRJ_PREFIX);
3358 }
3359
3360 static gint
3361 connector_download_data_snd (const gchar * path, GByteArray * output,
3362 struct job_control *control, void *data)
3363 {
3364 return connector_download_data_prefix (path, output, control, data,
3365 FS_DATA_SND_PREFIX);
3366 }
3367
3368 gchar *
3369 connector_get_sample_path_from_hash_size (struct connector *connector,
3370 guint32 hash, guint32 size)
3371 {
3372 guint32 aux32;
3373 gchar *path;
3374 GByteArray *rx_msg, *tx_msg =
3375 connector_new_msg (FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST,
3376 sizeof
3377 (FS_SAMPLE_GET_FILE_INFO_FROM_HASH_AND_SIZE_REQUEST));
3378
3379 aux32 = htobe32 (hash);
3380 memcpy (&tx_msg->data[5], &aux32, sizeof (guint32));
3381 aux32 = htobe32 (size);
3382 memcpy (&tx_msg->data[9], &aux32, sizeof (guint32));
3383
3384 rx_msg = connector_tx_and_rx (connector, tx_msg);
3385 if (!rx_msg)
3386 {
3387 return NULL;
3388 }
3389
3390 if (connector_get_msg_status (rx_msg))
3391 {
3392 path = strdup ((gchar *) & rx_msg->data[14]);
3393 }
3394 else
3395 {
3396 path = NULL;
3397 }
3398 g_byte_array_free (rx_msg, TRUE);
3399 return path;
3400 }
3401
3402 static gint
3403 connector_download_pkg (const gchar * path, GByteArray * output,
3404 struct job_control *control, void *data,
3405 enum package_type type,
3406 const struct fs_operations *ops,
3407 fs_remote_file_op download)
3408 {
3409 gint ret;
3410 gchar *pkg_name;
3411 struct package pkg;
3412 struct connector *connector = data;
3413
3414 pkg_name = connector_get_download_name (connector, NULL, ops, path);
3415 if (!pkg_name)
3416 {
3417 return -1;
3418 }
3419
3420 if (package_begin
3421 (&pkg, pkg_name, connector->fw_version, connector->device_desc, type))
3422 {
3423 g_free (pkg_name);
3424 return -1;
3425 }
3426
3427 ret =
3428 package_receive_pkg_resources (&pkg, path, control, connector, download,
3429 connector_download_sample_part);
3430 ret = ret || package_end (&pkg, output);
3431
3432 package_destroy (&pkg);
3433 return ret;
3434 }
3435
3436 static gint
3437 connector_download_data_snd_pkg (const gchar * path, GByteArray * output,
3438 struct job_control *control, void *data)
3439 {
3440 return connector_download_pkg (path, output, control, data,
3441 PKG_FILE_TYPE_SOUND,
3442 &FS_DATA_SND_OPERATIONS,
3443 connector_download_data_snd);
3444 }
3445
3446 static gint
3447 connector_download_data_prj_pkg (const gchar * path, GByteArray * output,
3448 struct job_control *control, void *data)
3449 {
3450 return connector_download_pkg (path, output, control, data,
3451 PKG_FILE_TYPE_PROJECT,
3452 &FS_DATA_PRJ_OPERATIONS,
3453 connector_download_data_prj);
3454 }
3455
3456 static gint
3457 connector_download_raw_pst_pkg (const gchar * path, GByteArray * output,
3458 struct job_control *control, void *data)
3459 {
3460 return connector_download_pkg (path, output, control, data,
3461 PKG_FILE_TYPE_PRESET,
3462 &FS_RAW_ANY_OPERATIONS,
3463 connector_download_raw);
3464 }
3465
3466 gchar *
3467 connector_get_upload_path (struct connector *connector,
3468 struct item_iterator *remote_iter,
3469 const struct fs_operations *ops,
3470 const gchar * dst_dir, const gchar * src_path,
3471 gint32 * next_index)
3472 {
3473 gchar *path, *indexs, *namec, *name, *aux;
3474 gboolean new;
3475
3476 if (ops->fs == FS_SAMPLES || ops->fs == FS_RAW_ALL
3477 || ops->fs == FS_RAW_PRESETS)
3478 {
3479 namec = strdup (src_path);
3480 name = basename (namec);
3481 remove_ext (name);
3482 aux = chain_path (dst_dir, name);
3483 g_free (namec);
3484
3485 if (ops->fs == FS_RAW_ALL || ops->fs == FS_RAW_PRESETS)
3486 {
3487 path = connector_add_ext_to_mc_snd (aux);
3488 g_free (aux);
3489 }
3490 else
3491 {
3492 path = aux;
3493 }
3494 return path;
3495 }
3496
3497 new = FALSE;
3498 if (!remote_iter)
3499 {
3500 new = TRUE;
3501 remote_iter = malloc (sizeof (struct item_iterator));
3502 if (ops->readdir (remote_iter, dst_dir, connector))
3503 {
3504 return strdup (dst_dir);
3505 }
3506 }
3507
3508 if (remote_iter->item.index == *next_index)
3509 {
3510 (*next_index)++;
3511 }
3512 else
3513 {
3514 while (!next_item_iterator (remote_iter))
3515 {
3516 if (remote_iter->item.index > *next_index)
3517 {
3518 break;
3519 }
3520 (*next_index)++;
3521 }
3522 }
3523
3524 if (new)
3525 {
3526 free_item_iterator (remote_iter);
3527 }
3528
3529 indexs = malloc (PATH_MAX);
3530 snprintf (indexs, PATH_MAX, "%d", *next_index);
3531 path = chain_path (dst_dir, indexs);
3532 g_free (indexs);
3533
3534 (*next_index)++;
3535
3536 return path;
3537 }
3538
3539 gchar *
3540 connector_get_download_name (struct connector *connector,
3541 struct item_iterator *remote_iter,
3542 const struct fs_operations *ops,
3543 const gchar * src_path)
3544 {
3545 gint32 id;
3546 const gchar *src_dir;
3547 gchar *namec, *name, *src_dirc;
3548 gint ret;
3549 gboolean new = FALSE;
3550
3551 namec = strdup (src_path);
3552 name = basename (namec);
3553
3554 if (ops->fs == FS_SAMPLES || ops->fs == FS_RAW_ALL
3555 || ops->fs == FS_RAW_PRESETS)
3556 {
3557 name = strdup (name);
3558 goto end;
3559 }
3560
3561 if (!remote_iter)
3562 {
3563 new = TRUE;
3564 remote_iter = malloc (sizeof (struct item_iterator));
3565 src_dirc = strdup (src_path);
3566 src_dir = dirname (src_dirc);
3567 ret = ops->readdir (remote_iter, src_dir, connector);
3568 g_free (src_dirc);
3569 if (ret)
3570 {
3571 name = NULL;
3572 goto cleanup;
3573 }
3574 }
3575
3576 id = atoi (name);
3577 name = NULL;
3578
3579 while (!next_item_iterator (remote_iter))
3580 {
3581 if (remote_iter->item.index == id)
3582 {
3583 name = get_item_name (&remote_iter->item);
3584 break;
3585 }
3586 }
3587
3588 cleanup:
3589 if (new)
3590 {
3591 free_item_iterator (remote_iter);
3592 }
3593 g_free (namec);
3594 end:
3595 return name;
3596 }
3597
3598 gchar *
3599 connector_get_download_path (struct connector *connector,
3600 struct item_iterator *remote_iter,
3601 const struct fs_operations *ops,
3602 const gchar * dst_dir, const gchar * src_path)
3603 {
3604 gchar *path, *src_pathc, *name, *dl_ext, *filename;
3605 const gchar *src_fpath, *md_ext, *ext = get_ext (src_path);
3606
3607 src_pathc = strdup (src_path);
3608 if (ext && strcmp (ext, "metadata") == 0 && ops->fs != FS_SAMPLES)
3609 {
3610 src_fpath = dirname (src_pathc);
3611 md_ext = ".metadata";
3612 }
3613 else
3614 {
3615 src_fpath = src_pathc;
3616 md_ext = "";
3617 }
3618
3619 name = connector_get_download_name (connector, remote_iter, ops, src_fpath);
3620 if (name)
3621 {
3622 dl_ext = connector_get_full_ext (connector->device_desc, ops);
3623 filename = malloc (PATH_MAX);
3624 snprintf (filename, PATH_MAX, "%s.%s%s", name, dl_ext, md_ext);
3625 path = chain_path (dst_dir, filename);
3626 g_free (name);
3627 g_free (dl_ext);
3628 g_free (filename);
3629 }
3630 else
3631 {
3632 path = NULL;
3633 }
3634
3635 g_free (src_pathc);
3636 return path;
3637 }
3638
3639 static gint
3640 connector_upload_data_prefix (const gchar * path, GByteArray * array,
3641 struct job_control *control, void *data,
3642 const gchar * prefix)
3643 {
3644 gint res;
3645 guint32 seq;
3646 guint32 jid;
3647 guint32 crc;
3648 guint32 len;
3649 guint32 r_jid;
3650 guint32 r_seq;
3651 guint32 offset;
3652 guint32 *data32;
3653 guint32 jidbe;
3654 guint32 aux32;
3655 gboolean active;
3656 guint32 total;
3657 GByteArray *rx_msg;
3658 GByteArray *tx_msg;
3659 gchar *path_w_prefix = connector_add_prefix_to_path (path, prefix);
3660 struct connector *connector = data;
3661
3662 res =
3663 connector_open_datum (connector, path_w_prefix, &jid, O_WRONLY,
3664 array->len);
3665 g_free (path_w_prefix);
3666 if (res)
3667 {
3668 goto end;
3669 }
3670
3671 usleep (REST_TIME);
3672
3673 jidbe = htobe32 (jid);
3674
3675 seq = 0;
3676 offset = 0;
3677 control->data = NULL;
3678 if (control)
3679 {
3680 g_mutex_lock (&control->mutex);
3681 active = control->active;
3682 g_mutex_unlock (&control->mutex);
3683 }
3684 else
3685 {
3686 active = TRUE;
3687 }
3688
3689 while (offset < array->len && active)
3690 {
3691 tx_msg =
3692 connector_new_msg (DATA_WRITE_PARTIAL_REQUEST,
3693 sizeof (DATA_WRITE_PARTIAL_REQUEST));
3694 g_byte_array_append (tx_msg, (guint8 *) & jidbe, sizeof (guint32));
3695 aux32 = htobe32 (seq);
3696 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3697
3698 if (offset + DATA_TRANSF_BLOCK_BYTES < array->len)
3699 {
3700 len = DATA_TRANSF_BLOCK_BYTES;
3701 }
3702 else
3703 {
3704 len = array->len - offset;
3705 }
3706
3707 crc = crc32 (0xffffffff, &array->data[offset], len);
3708 aux32 = htobe32 (crc);
3709 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3710
3711 aux32 = htobe32 (len);
3712 g_byte_array_append (tx_msg, (guint8 *) & aux32, sizeof (guint32));
3713
3714 g_byte_array_append (tx_msg, &array->data[offset], len);
3715
3716 rx_msg = connector_tx_and_rx (connector, tx_msg);
3717 if (!rx_msg)
3718 {
3719 res = -EIO;
3720 goto end;
3721 }
3722
3723 usleep (REST_TIME);
3724
3725 if (!connector_get_msg_status (rx_msg))
3726 {
3727 res = -EPERM;
3728 error_print ("%s (%s)\n", snd_strerror (res),
3729 connector_get_msg_string (rx_msg));
3730 free_msg (rx_msg);
3731 break;
3732 }
3733
3734 data32 = (guint32 *) & rx_msg->data[6];
3735 r_jid = be32toh (*data32);
3736
3737 data32 = (guint32 *) & rx_msg->data[10];
3738 r_seq = be32toh (*data32);
3739
3740 data32 = (guint32 *) & rx_msg->data[14];
3741 total = be32toh (*data32);
3742
3743 free_msg (rx_msg);
3744
3745 debug_print (1,
3746 "Write datum info: job id: %d; seq: %d; total: %d\n",
3747 r_jid, r_seq, total);
3748
3749 seq++;
3750 offset += len;
3751
3752 if (total != offset)
3753 {
3754 error_print
3755 ("Actual upload bytes (%d) differs from expected ones (%d)\n",
3756 total, offset);
3757 }
3758
3759 if (control)
3760 {
3761 set_job_control_progress (control, offset / (gdouble) array->len);
3762 g_mutex_lock (&control->mutex);
3763 active = control->active;
3764 g_mutex_unlock (&control->mutex);
3765 }
3766 }
3767
3768 debug_print (2, "%d bytes sent\n", offset);
3769
3770 res = connector_close_datum (connector, jid, O_WRONLY, array->len);
3771
3772 end:
3773 return res;
3774 }
3775
3776 static gint
3777 connector_upload_data_any (const gchar * path, GByteArray * array,
3778 struct job_control *control, void *data)
3779 {
3780 control->parts = 1;
3781 control->part = 0;
3782 return connector_upload_data_prefix (path, array, control, data, NULL);
3783 }
3784
3785 static gint
3786 connector_upload_data_prj (const gchar * path, GByteArray * array,
3787 struct job_control *control, void *data)
3788 {
3789 return connector_upload_data_prefix (path, array, control, data,
3790 FS_DATA_PRJ_PREFIX);
3791 }
3792
3793 static gint
3794 connector_upload_data_snd (const gchar * path, GByteArray * array,
3795 struct job_control *control, void *data)
3796 {
3797 return connector_upload_data_prefix (path, array, control, data,
3798 FS_DATA_SND_PREFIX);
3799 }
3800
3801 static gint
3802 connector_upload_pkg (const gchar * path, GByteArray * input,
3803 struct job_control *control, void *data,
3804 guint8 type, const struct fs_operations *ops,
3805 fs_remote_file_op upload)
3806 {
3807 gint ret;
3808 struct package pkg;
3809 struct connector *connector = data;
3810
3811 ret = package_open (&pkg, input, connector->device_desc);
3812 if (!ret)
3813 {
3814 ret = package_send_pkg_resources (&pkg, path, control, connector,
3815 upload, connector_upload_sample_part);
3816 package_close (&pkg);
3817 }
3818 return ret;
3819 }
3820
3821 static gint
3822 connector_upload_data_snd_pkg (const gchar * path, GByteArray * input,
3823 struct job_control *control, void *data)
3824 {
3825 return connector_upload_pkg (path, input, control, data,
3826 PKG_FILE_TYPE_SOUND,
3827 &FS_DATA_SND_OPERATIONS,
3828 connector_upload_data_snd);
3829 }
3830
3831 static gint
3832 connector_upload_data_prj_pkg (const gchar * path, GByteArray * input,
3833 struct job_control *control, void *data)
3834 {
3835 return connector_upload_pkg (path, input, control, data,
3836 PKG_FILE_TYPE_PROJECT,
3837 &FS_DATA_PRJ_OPERATIONS,
3838 connector_upload_data_prj);
3839 }
3840
3841 static gint
3842 connector_upload_raw_pst_pkg (const gchar * path, GByteArray * input,
3843 struct job_control *control, void *data)
3844 {
3845 return connector_upload_pkg (path, input, control, data,
3846 PKG_FILE_TYPE_PRESET,
3847 &FS_RAW_ANY_OPERATIONS, connector_upload_raw);
3848 }
3849
3850 gchar *
3851 connector_get_full_ext (const struct connector_device_desc *desc,
3852 const struct fs_operations *ops)
3853 {
3854 gchar *ext = malloc (LABEL_MAX);
3855 if (ops->fs == FS_SAMPLES)
3856 {
3857 snprintf (ext, LABEL_MAX, "%s", ops->extension);
3858 }
3859 else
3860 {
3861 snprintf (ext, LABEL_MAX, "%s%s", desc->alias, ops->extension);
3862 }
3863 return ext;
3864 }
3865
3866 void
3867 connector_enable_dir_cache (struct connector *connector)
3868 {
3869 g_mutex_lock (&connector->mutex);
3870 connector->dir_cache =
3871 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_msg);
3872 g_mutex_unlock (&connector->mutex);
3873 }
3874
3875 void
3876 connector_disable_dir_cache (struct connector *connector)
3877 {
3878 g_mutex_lock (&connector->mutex);
3879 g_hash_table_destroy (connector->dir_cache);
3880 connector->dir_cache = NULL;
3881 g_mutex_unlock (&connector->mutex);
3882 }
1919
2020 #include <glib.h>
2121 #include <alsa/asoundlib.h>
22 #include "utils.h"
23
24 #ifndef CONNECTOR_H
25 #define CONNECTOR_H
2226
2327 #define SYSEX_TIMEOUT 5000
24
25 #define CAP_SAMPLE 0b00000001
28 #define REST_TIME 50000
2629
2730 struct connector_device_desc
2831 {
32 const gchar *name;
33 const gchar *alias;
2934 guint8 id;
30 gchar *model;
31 guint8 capabilities;
32 guint8 startup_mode;
35 guint8 fss;
36 guint8 storages;
3337 };
3438
3539 struct connector
3842 snd_rawmidi_t *inputp;
3943 snd_rawmidi_t *outputp;
4044 gchar *device_name;
45 gchar *alias;
46 gchar *fw_version;
4147 gushort seq;
4248 GMutex mutex;
4349 ssize_t rx_len;
4450 guint8 *buffer;
4551 gint npfds;
4652 struct pollfd *pfds;
53 GHashTable *dir_cache;
4754 };
4855
49 struct connector_dir_iterator
56 enum connector_fs
5057 {
51 gchar *dentry;
52 gchar type;
53 guint size;
54 guint32 cksum;
58 FS_SAMPLES = 0x1,
59 FS_RAW_ALL = 0x2,
60 FS_RAW_PRESETS = 0x4,
61 FS_DATA_ALL = 0x8,
62 FS_DATA_PRJ = 0x10,
63 FS_DATA_SND = 0x20,
64 };
65
66 struct connector_iterator_data
67 {
5568 GByteArray *msg;
56 guint pos;
69 guint32 pos;
70 guint32 hash;
71 guint16 operations;
72 guint8 has_valid_data;
73 guint8 has_metadata;
74 enum connector_fs fs;
75 gboolean cached;
5776 };
5877
5978 struct connector_system_device
7796 gint timeout; //Measured in ms. -1 is infinite.
7897 gboolean batch;
7998 GMutex mutex;
99 GByteArray *raw;
80100 };
81101
82 struct connector_sample_transfer
102 enum connector_storage
83103 {
84 gboolean active;
85 GMutex mutex;
104 STORAGE_PLUS_DRIVE = 0x1,
105 STORAGE_RAM = 0x2
86106 };
87107
88 enum connector_fs_type
89 {
90 FS_NONE,
91 FS_PLUS_DRIVE,
92 FS_RAM
93 };
94
95 struct connector_statfs
108 struct connector_storage_stats
96109 {
97110 const gchar *name;
98111 guint64 bsize;
99112 guint64 bfree;
100113 };
114
115 const struct fs_operations *connector_get_fs_operations (enum connector_fs);
101116
102117 gint connector_init (struct connector *, gint);
103118
105120
106121 gboolean connector_check (struct connector *);
107122
108 struct connector_dir_iterator *connector_read_dir (struct connector *,
109 const gchar *);
110
111 void connector_free_dir_iterator (struct connector_dir_iterator *);
112
113 guint connector_get_next_dentry (struct connector_dir_iterator *);
114
115 gint connector_rename (struct connector *, const gchar *, const gchar *);
116
117 gint connector_delete_file (struct connector *, const gchar *);
118
119 gint connector_delete_dir (struct connector *, const gchar *);
120
121 GArray *connector_download (struct connector *, const gchar *,
122 struct connector_sample_transfer *,
123 void (*)(gdouble));
124
125 ssize_t
126 connector_upload (struct connector *, GArray *, gchar *,
127 struct connector_sample_transfer *, void (*)(gdouble));
128
129 void connector_get_sample_info_from_msg (GByteArray *, gint *, guint *);
130
131 gint connector_create_dir (struct connector *, const gchar *);
132
133123 GArray *connector_get_system_devices ();
134124
135 ssize_t connector_tx_sysex (struct connector *, GByteArray *,
136 struct connector_sysex_transfer *);
125 gint connector_tx_sysex (struct connector *,
126 struct connector_sysex_transfer *);
137127
138 GByteArray *connector_rx_sysex (struct connector *,
139 struct connector_sysex_transfer *);
140
128 gint connector_rx_sysex (struct connector *,
129 struct connector_sysex_transfer *);
141130
142131 void connector_rx_drain (struct connector *);
143132
144 gint connector_upgrade_os (struct connector *, GByteArray *,
133 gint connector_upgrade_os (struct connector *,
145134 struct connector_sysex_transfer *);
146135
147 void free_msg (gpointer);
136 gint connector_get_storage_stats (struct connector *,
137 enum connector_storage,
138 struct connector_storage_stats *);
148139
149 gint connector_statfs (struct connector *, enum connector_fs_type,
150 struct connector_statfs *);
140 gdouble connector_get_storage_stats_percent (struct connector_storage_stats
141 *);
151142
152 float connector_statfs_use_percent (struct connector_statfs *);
143 gchar *connector_get_upload_path (struct connector *, struct item_iterator *,
144 const struct fs_operations *, const gchar *,
145 const gchar *, gint32 *);
146
147 gchar *connector_get_download_name (struct connector *,
148 struct item_iterator *,
149 const struct fs_operations *,
150 const gchar *);
151
152 gchar *connector_get_download_path (struct connector *,
153 struct item_iterator *,
154 const struct fs_operations *,
155 const gchar *, const gchar *);
156
157
158 gchar *connector_get_full_ext (const struct connector_device_desc *,
159 const struct fs_operations *);
160
161 gchar *connector_get_sample_path_from_hash_size (struct connector *,
162 guint32, guint32);
163
164 void connector_enable_dir_cache (struct connector *);
165
166 void connector_disable_dir_cache (struct connector *);
167
168 #endif
2525 #include <signal.h>
2626 #include <stdint.h>
2727 #include <inttypes.h>
28 #include <stddef.h>
2829 #include "connector.h"
29 #include "sample.h"
3030 #include "utils.h"
3131
32 #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))))
34 #define CHECK_FS_OPS_FUNC(f) if (!(f)) {error_print ("Operation not implemented\n"); return EXIT_FAILURE;}
35
3236 static struct connector connector;
33 static struct connector_sample_transfer sample_transfer;
34
35 static gchar *
37 static struct job_control control;
38
39 typedef void (*print_item) (struct item_iterator *);
40
41 static const gchar *CLI_FSS[] = {
42 "sample", "raw", "preset", "data", "project", "sound"
43 };
44
45 static void
46 print_smplrw (struct item_iterator *iter)
47 {
48 gchar *hsize = get_human_size (iter->item.size, FALSE);
49 struct connector_iterator_data *data = iter->data;
50
51 printf ("%c %10s %08x %s\n", iter->item.type,
52 hsize, data->hash, iter->item.name);
53 g_free (hsize);
54 }
55
56 static void
57 print_data (struct item_iterator *iter)
58 {
59 gchar *hsize = get_human_size (iter->item.size, FALSE);
60 struct connector_iterator_data *data = iter->data;
61
62 printf ("%c %3d %04x %d %d %10s %s\n", iter->item.type,
63 iter->item.index, data->operations, data->has_valid_data,
64 data->has_metadata, hsize, iter->item.name);
65 g_free (hsize);
66 }
67
68 static void
69 null_control_callback (gdouble foo)
70 {
71 }
72
73 static const gchar *
3674 cli_get_path (gchar * device_path)
3775 {
3876 gint len = strlen (device_path);
67105 }
68106
69107 static gint
70 cli_connect (const char *device_path)
108 cli_connect (const char *device_path, enum connector_fs fs)
71109 {
72110 gint card = atoi (device_path);
73 return connector_init (&connector, card);
111 gint ret = connector_init (&connector, card);
112 if (!ret && fs && !(connector.device_desc->fss & fs))
113 {
114 error_print ("Filesystem not supported for device '%s'\n",
115 connector.device_desc->name);
116 return 1;
117 }
118 return ret;
74119 }
75120
76121 static int
77 cli_ls (int argc, char *argv[], int optind)
78 {
79 struct connector_dir_iterator *d_iter;
80 gchar *device_path, *path;
81 gint res;
122 cli_list (int argc, char *argv[], int optind, enum connector_fs fs,
123 print_item print)
124 {
125 const gchar *path;
126 struct item_iterator iter;
127 gchar *device_path;
128 const struct fs_operations *fs_ops = connector_get_fs_operations (fs);
82129
83130 if (optind == argc)
84131 {
90137 device_path = argv[optind];
91138 }
92139
93 res = cli_connect (device_path);
94
95 if (res < 0)
140 if (cli_connect (device_path, fs))
96141 {
97142 return EXIT_FAILURE;
98143 }
99144
100145 path = cli_get_path (device_path);
101146
102 d_iter = connector_read_dir (&connector, path);
103 if (!d_iter)
104 {
105 return EXIT_FAILURE;
106 }
107
108 while (!connector_get_next_dentry (d_iter))
109 {
110 printf ("%c %.2f %08x %s\n", d_iter->type,
111 d_iter->size / (1024.0 * 1024.0), d_iter->cksum,
112 d_iter->dentry);
113 }
114
115 connector_free_dir_iterator (d_iter);
147 if (fs_ops->readdir (&iter, path, &connector))
148 {
149 return EXIT_FAILURE;
150 }
151
152 while (!next_item_iterator (&iter))
153 {
154 print (&iter);
155 }
156
157 free_item_iterator (&iter);
116158
117159 return EXIT_SUCCESS;
118160 }
119161
120162 static int
121 cli_mkdir (int argc, char *argv[], int optind)
122 {
123 gchar *device_path, *path;
124 gint res;
163 cli_command_path (int argc, char *argv[], int optind, enum connector_fs fs,
164 ssize_t member_offset)
165 {
166 const gchar *path;
167 gchar *device_path;
168 gint ret;
169 fs_path_func f;
125170
126171 if (optind == argc)
127172 {
133178 device_path = argv[optind];
134179 }
135180
136 res = cli_connect (device_path);
137
138 if (res < 0)
181 if (cli_connect (device_path, fs))
139182 {
140183 return EXIT_FAILURE;
141184 }
142185
143186 path = cli_get_path (device_path);
144187
145 return connector_create_dir (&connector, path);
188 f = GET_FS_OPS_FUNC (fs_path_func, fs, member_offset);
189 CHECK_FS_OPS_FUNC (f);
190 ret = f (path, &connector);
191 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
146192 }
147193
148194 static int
149 cli_mv (int argc, char *argv[], int optind)
150 {
151 gchar *device_path_src, *device_path_dst, *path_src, *path_dst;
152 gint card_src;
153 gint card_dst;
154 gint res;
195 cli_command_src_dst (int argc, char *argv[], int optind, enum connector_fs fs,
196 ssize_t member_offset)
197 {
198 const gchar *src_path, *dst_path;
199 gchar *device_src_path, *device_dst_path;
200 gint src_card;
201 gint dst_card;
202 int ret;
203 fs_src_dst_func f;
155204
156205 if (optind == argc)
157206 {
160209 }
161210 else
162211 {
163 device_path_src = argv[optind];
212 device_src_path = argv[optind];
164213 optind++;
165214 }
166215
171220 }
172221 else
173222 {
174 device_path_dst = argv[optind];
175 }
176
177 card_src = atoi (device_path_src);
178 card_dst = atoi (device_path_dst);
179 if (card_src != card_dst)
223 device_dst_path = argv[optind];
224 }
225
226 src_card = atoi (device_src_path);
227 dst_card = atoi (device_dst_path);
228 if (src_card != dst_card)
180229 {
181230 error_print ("Source and destination device must be the same\n");
182231 return EXIT_FAILURE;
183232 }
184233
185 res = cli_connect (device_path_src);
186
187 if (res < 0)
188 {
189 return EXIT_FAILURE;
190 }
191
192 path_src = cli_get_path (device_path_src);
193 path_dst = cli_get_path (device_path_dst);
194
195 return connector_rename (&connector, path_src, path_dst);
196 }
197
198 static int
199 cli_delete (int argc, char *argv[], int optind, char type)
200 {
201 gchar *device_path, *path;
202 gint res;
203
204 if (optind == argc)
205 {
206 error_print ("Remote path missing\n");
207 return EXIT_FAILURE;
208 }
209 else
210 {
211 device_path = argv[optind];
212 }
213
214 res = cli_connect (device_path);
215
216 if (res < 0)
217 {
218 return EXIT_FAILURE;
219 }
220
221 path = cli_get_path (device_path);
222
223 if (type == ELEKTROID_FILE)
224 {
225 res = connector_delete_file (&connector, path);
226 }
227 else if (type == ELEKTROID_DIR)
228 {
229 res = connector_delete_dir (&connector, path);
230 }
231 else
232 {
233 res = -1;
234 }
235
236 return res;
237 }
238
239 static int
240 cli_download (int argc, char *argv[], int optind)
241 {
242 gchar *device_path_src, *path_src, *local_path;
243 gint res;
244 GArray *data;
245 ssize_t frames;
246 gchar *basec, *bname;
247
248 if (optind == argc)
249 {
250 error_print ("Remote path missing\n");
251 return EXIT_FAILURE;
252 }
253 else
254 {
255 device_path_src = argv[optind];
256 }
257
258 res = cli_connect (device_path_src);
259
260 if (res < 0)
261 {
262 return EXIT_FAILURE;
263 }
264
265 path_src = cli_get_path (device_path_src);
266
267 sample_transfer.active = TRUE;
268 data = connector_download (&connector, path_src, &sample_transfer, NULL);
269 if (data == NULL)
270 {
271 return EXIT_FAILURE;
272 }
273
274 basec = strdup (path_src);
275 bname = basename (basec);
276 local_path = malloc (PATH_MAX);
277 snprintf (local_path, PATH_MAX, "./%s.wav", bname);
278
279 frames = sample_save (data, local_path);
280
281 free (basec);
282 free (local_path);
283 g_array_free (data, TRUE);
284
285 return frames > 0 ? EXIT_SUCCESS : EXIT_FAILURE;
286 }
287
288 static int
289 cli_upload (int argc, char *argv[], int optind)
290 {
291 gchar *path_src, *device_path_dst, *path_dst;
292 gint res;
293 ssize_t frames;
294 gchar *basec, *bname;
295 GArray *sample;
296
297 if (optind == argc)
298 {
299 error_print ("Local path missing\n");
300 return EXIT_FAILURE;
301 }
302 else
303 {
304 path_src = argv[optind];
305 optind++;
306 }
307
308 if (optind == argc)
309 {
310 error_print ("Remote path missing\n");
311 return EXIT_FAILURE;
312 }
313 else
314 {
315 device_path_dst = argv[optind];
316 }
317
318 res = cli_connect (device_path_dst);
319
320 if (res < 0)
321 {
322 return EXIT_FAILURE;
323 }
324
325 basec = strdup (path_src);
326 bname = basename (basec);
327 remove_ext (bname);
328 path_dst = cli_get_path (device_path_dst);
329 path_dst = chain_path (path_dst, bname);
330
331 sample = g_array_new (FALSE, FALSE, sizeof (short));
332 frames = sample_load (sample, NULL, NULL, path_src, NULL, NULL);
333 if (frames < 0)
334 {
335 res = EXIT_FAILURE;
336 goto cleanup;
337 }
338
339 sample_transfer.active = TRUE;
340 frames =
341 connector_upload (&connector, sample, path_dst, &sample_transfer, NULL);
342
343 res = frames < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
344
345 cleanup:
346 free (basec);
347 free (path_dst);
348 g_array_free (sample, TRUE);
349 return res;
234 if (cli_connect (device_src_path, 0))
235 {
236 return EXIT_FAILURE;
237 }
238
239 f = GET_FS_OPS_FUNC (fs_src_dst_func, fs, member_offset);
240 CHECK_FS_OPS_FUNC (f);
241 src_path = cli_get_path (device_src_path);
242 dst_path = cli_get_path (device_dst_path);
243 ret = f (src_path, dst_path, &connector);
244 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
350245 }
351246
352247 static int
353248 cli_info (int argc, char *argv[], int optind)
354249 {
355250 gchar *device_path;
356 gint res;
251 gchar *comma;
357252
358253 if (optind == argc)
359254 {
365260 device_path = argv[optind];
366261 }
367262
368 res = cli_connect (device_path);
369
370 if (res < 0)
371 {
372 return EXIT_FAILURE;
373 }
374
375 printf ("%s\n", connector.device_name);
263 if (cli_connect (device_path, 0))
264 {
265 return EXIT_FAILURE;
266 }
267
268 printf ("%s filesystems=", connector.device_name);
269 comma = "";
270 for (int fs = FS_SAMPLES, i = 0; fs <= FS_DATA_SND; fs <<= 1, i++)
271 {
272 if (connector.device_desc->fss & fs)
273 {
274 printf ("%s%s", comma, CLI_FSS[i]);
275 }
276 comma = ",";
277 }
278 printf ("\n");
376279
377280 return EXIT_SUCCESS;
378281 }
381284 cli_df (int argc, char *argv[], int optind)
382285 {
383286 gchar *device_path;
287 gchar *size;
288 gchar *diff;
289 gchar *free;
384290 gint res;
385 struct connector_statfs statfs;
386 enum connector_fs_type fs;
291 struct connector_storage_stats statfs;
292 enum connector_storage storage;
387293
388294 if (optind == argc)
389295 {
395301 device_path = argv[optind];
396302 }
397303
398 res = cli_connect (device_path);
399
400 if (res < 0)
401 {
402 return EXIT_FAILURE;
403 }
404
405 printf ("%-10.10s%16.16s%16.16s%16.16s%11.10s\n", "Filesystem", "Size",
304 if (cli_connect (device_path, 0))
305 {
306 return EXIT_FAILURE;
307 }
308
309 if (!connector.device_desc->storages)
310 {
311 return EXIT_FAILURE;
312 }
313
314 printf ("%-10.10s%16.16s%16.16s%16.16s%11.10s\n", "Storage", "Size",
406315 "Used", "Available", "Use%");
407316
408 for (fs = FS_PLUS_DRIVE; fs <= FS_RAM; fs++)
409 {
410 res = connector_statfs (&connector, fs, &statfs);
411 printf ("%-10.10s%16" PRId64 "%16" PRId64 "%16" PRId64 "%10.2f%%\n",
412 statfs.name, statfs.bsize, statfs.bsize - statfs.bfree,
413 statfs.bfree, connector_statfs_use_percent (&statfs));
414 }
415
416 return EXIT_SUCCESS;
317 res = 0;
318 for (storage = STORAGE_PLUS_DRIVE; storage <= STORAGE_RAM; storage <<= 1)
319 {
320 if (connector.device_desc->storages & storage)
321 {
322 res |= connector_get_storage_stats (&connector, storage, &statfs);
323 if (res)
324 {
325 continue;
326 }
327 size = get_human_size (statfs.bsize, FALSE);
328 diff = get_human_size (statfs.bsize - statfs.bfree, FALSE);
329 free = get_human_size (statfs.bfree, FALSE);
330 printf ("%-10.10s%16s%16s%16s%10.2f%%\n",
331 statfs.name, size, diff, free,
332 connector_get_storage_stats_percent (&statfs));
333 g_free (size);
334 g_free (diff);
335 g_free (free);
336 }
337 }
338
339 return res ? EXIT_FAILURE : EXIT_SUCCESS;
340 }
341
342 static int
343 cli_upgrade (int argc, char *argv[], int optind)
344 {
345 gint res;
346 const gchar *src_path;
347 const gchar *device_path;
348 struct connector_sysex_transfer sysex_transfer;
349
350 if (optind == argc)
351 {
352 error_print ("Local path missing\n");
353 return EXIT_FAILURE;
354 }
355 else
356 {
357 src_path = argv[optind];
358 optind++;
359 }
360
361 if (optind == argc)
362 {
363 error_print ("Remote path missing\n");
364 return EXIT_FAILURE;
365 }
366 else
367 {
368 device_path = argv[optind];
369 }
370
371 if (cli_connect (device_path, 0))
372 {
373 return EXIT_FAILURE;
374 }
375
376 sysex_transfer.raw = g_byte_array_new ();
377 res = load_file (src_path, sysex_transfer.raw, NULL);
378 if (res)
379 {
380 error_print ("Error while loading '%s'.\n", src_path);
381 }
382 else
383 {
384 sysex_transfer.active = TRUE;
385 sysex_transfer.timeout = SYSEX_TIMEOUT;
386 res = connector_upgrade_os (&connector, &sysex_transfer);
387 }
388
389 g_byte_array_free (sysex_transfer.raw, TRUE);
390 return res ? EXIT_FAILURE : EXIT_SUCCESS;
391 }
392
393 static int
394 cli_download (int argc, char *argv[], int optind, enum connector_fs fs)
395 {
396 const gchar *src_path;
397 gchar *device_src_path, *download_path;
398 gint res;
399 GByteArray *array;
400 const struct fs_operations *fs_ops;
401
402 if (optind == argc)
403 {
404 error_print ("Remote path missing\n");
405 return EXIT_FAILURE;
406 }
407 else
408 {
409 device_src_path = argv[optind];
410 }
411
412 if (cli_connect (device_src_path, fs))
413 {
414 return EXIT_FAILURE;
415 }
416
417 fs_ops = connector_get_fs_operations (fs);
418 src_path = cli_get_path (device_src_path);
419
420 control.active = TRUE;
421 control.callback = null_control_callback;
422 array = g_byte_array_new ();
423 res = fs_ops->download (src_path, array, &control, &connector);
424 if (res)
425 {
426 goto end;
427 }
428
429 download_path = connector_get_download_path (&connector, NULL, fs_ops, ".",
430 src_path);
431 if (!download_path)
432 {
433 res = -1;
434 goto end;
435 }
436
437 res = fs_ops->save (download_path, array, &control);
438 g_free (download_path);
439 g_free (control.data);
440
441 end:
442 g_byte_array_free (array, TRUE);
443 return res ? EXIT_FAILURE : EXIT_SUCCESS;
444 }
445
446 static int
447 cli_upload (int argc, char *argv[], int optind, enum connector_fs fs)
448 {
449 const gchar *dst_dir;
450 gchar *src_path, *device_dst_path, *upload_path;
451 gint res;
452 GByteArray *array;
453 gint32 index = 1;
454 const struct fs_operations *fs_ops;
455
456 if (optind == argc)
457 {
458 error_print ("Local path missing\n");
459 return EXIT_FAILURE;
460 }
461 else
462 {
463 src_path = argv[optind];
464 optind++;
465 }
466
467 if (optind == argc)
468 {
469 error_print ("Remote path missing\n");
470 return EXIT_FAILURE;
471 }
472 else
473 {
474 device_dst_path = argv[optind];
475 }
476
477 if (cli_connect (device_dst_path, fs))
478 {
479 return EXIT_FAILURE;
480 }
481
482 fs_ops = connector_get_fs_operations (fs);
483 dst_dir = cli_get_path (device_dst_path);
484
485 upload_path = connector_get_upload_path (&connector, NULL, fs_ops,
486 dst_dir, src_path, &index);
487
488 array = g_byte_array_new ();
489 control.active = TRUE;
490 control.callback = null_control_callback;
491 res = fs_ops->load (src_path, array, &control);
492 if (res)
493 {
494 goto cleanup;
495 }
496
497 res = fs_ops->upload (upload_path, array, &control, &connector);
498 g_free (control.data);
499
500 cleanup:
501 g_free (upload_path);
502 g_byte_array_free (array, TRUE);
503 return res ? EXIT_FAILURE : EXIT_SUCCESS;
504 }
505
506 static gint
507 get_fs_operations_from_type (const gchar * type)
508 {
509 if (!strlen (type))
510 {
511 return 0;
512 }
513
514 for (gint fs = FS_SAMPLES, i = 0; fs <= FS_DATA_SND; fs <<= 1, i++)
515 {
516 if (strcmp (type, CLI_FSS[i]) == 0)
517 {
518 return fs;
519 }
520 }
521
522 return -1;
523 }
524
525 static gint
526 get_op_type_from_command (const gchar * cmd, char *op, char *type)
527 {
528 gint i;
529 gchar *c;
530 gint len;
531
532 strncpy (op, cmd, LABEL_MAX);
533 op[LABEL_MAX - 1] = 0;
534 len = strlen (op);
535 c = op;
536 for (i = 0; i < LABEL_MAX && i < strlen (op); i++, c++)
537 {
538 if (*c == '-')
539 {
540 *c = 0;
541 break;
542 }
543 }
544 if (i < len - 1)
545 {
546 c++;
547 strncpy (type, c, LABEL_MAX);
548 type[LABEL_MAX - 1] = 0;
549 }
550 else
551 {
552 *type = 0;
553 }
554
555 return get_fs_operations_from_type (type);
417556 }
418557
419558 static void
420559 cli_end (int sig)
421560 {
422 sample_transfer.active = FALSE;
561 control.active = FALSE;
423562 }
424563
425564 int
430569 gchar *command;
431570 gint vflg = 0, errflg = 0;
432571 struct sigaction action, old_action;
572 gint fs;
573 char op[LABEL_MAX];
574 char type[LABEL_MAX];
433575
434576 action.sa_handler = cli_end;
435577 sigemptyset (&action.sa_mask);
494636 exit (EXIT_FAILURE);
495637 }
496638
497 if (strcmp (command, "ld") == 0)
498 {
499 res = cli_ld ();
500 }
501 else if (strcmp (command, "ls") == 0)
502 {
503 res = cli_ls (argc, argv, optind);
504 }
505 else if (strcmp (command, "mkdir") == 0)
506 {
507 res = cli_mkdir (argc, argv, optind);
508 }
509 else if (strcmp (command, "mv") == 0)
510 {
511 res = cli_mv (argc, argv, optind);
512 }
513 else if (strcmp (command, "rm") == 0)
514 {
515 res = cli_delete (argc, argv, optind, ELEKTROID_FILE);
516 }
517 else if (strcmp (command, "rmdir") == 0)
518 {
519 res = cli_delete (argc, argv, optind, ELEKTROID_DIR);
520 }
521 else if (strcmp (command, "download") == 0)
522 {
523 res = cli_download (argc, argv, optind);
524 }
525 else if (strcmp (command, "upload") == 0)
526 {
527 res = cli_upload (argc, argv, optind);
528 }
529 else if (strcmp (command, "info") == 0)
530 {
531 res = cli_info (argc, argv, optind);
532 }
533 else if (strcmp (command, "df") == 0)
534 {
535 res = cli_df (argc, argv, optind);
536 }
537 else
538 {
539 error_print ("Command %s not recognized\n", command);
639 fs = get_op_type_from_command (command, op, type);
640 debug_print (1, "Operation: '%s'; filesystem: '%s' (%d)\n", op, type, fs);
641 if (fs < 0)
642 {
643 error_print ("Filesystem '%s' not recognized\n", type);
540644 res = EXIT_FAILURE;
541 }
542
645 goto end;
646 }
647
648 if (!fs)
649 {
650 if (strcmp (command, "ld") == 0
651 || strcmp (command, "list-devices") == 0)
652 {
653 res = cli_ld ();
654 }
655 else if (strcmp (op, "info") == 0
656 || strcmp (command, "info-devices") == 0)
657 {
658 res = cli_info (argc, argv, optind);
659 }
660 else if (strcmp (command, "df") == 0
661 || strcmp (command, "info-storage") == 0)
662 {
663 res = cli_df (argc, argv, optind);
664 }
665 else if (strcmp (command, "upgrade") == 0)
666 {
667 res = cli_upgrade (argc, argv, optind);
668 }
669 else if (strcmp (command, "ls") == 0)
670 {
671 res = cli_list (argc, argv, optind, FS_SAMPLES, print_smplrw);
672 }
673 else if (strcmp (command, "mkdir") == 0)
674 {
675 res =
676 cli_command_path (argc, argv, optind, FS_SAMPLES,
677 GET_FS_OPS_OFFSET (mkdir));
678 }
679 else if (strcmp (command, "mv") == 0)
680 {
681 res =
682 cli_command_src_dst (argc, argv, optind, FS_SAMPLES,
683 GET_FS_OPS_OFFSET (move));
684 }
685 else if (strcmp (command, "rm") == 0 || strcmp (command, "rmdir") == 0)
686 {
687 res =
688 cli_command_path (argc, argv, optind, FS_SAMPLES,
689 GET_FS_OPS_OFFSET (delete));
690 }
691 else if (strcmp (command, "download") == 0
692 || strcmp (command, "dl") == 0)
693 {
694 res = cli_download (argc, argv, optind, FS_SAMPLES);
695 }
696 else if (strcmp (command, "upload") == 0 || strcmp (command, "ul") == 0)
697 {
698 res = cli_upload (argc, argv, optind, FS_SAMPLES);
699 }
700 else
701 {
702 error_print ("Command '%s' not recognized\n", command);
703 res = EXIT_FAILURE;
704 }
705 goto end;
706 }
707
708 if (strcmp (op, "ls") == 0 || strcmp (op, "list") == 0)
709 {
710 print_item print = (fs == FS_SAMPLES || fs == FS_RAW_ALL
711 || fs ==
712 FS_RAW_PRESETS) ? print_smplrw : print_data;
713 res = cli_list (argc, argv, optind, fs, print);
714 }
715 else if (strcmp (op, "mkdir") == 0)
716 {
717 res =
718 cli_command_path (argc, argv, optind, fs, GET_FS_OPS_OFFSET (mkdir));
719 }
720 else if (strcmp (op, "rm") == 0 || strcmp (op, "rmdir") == 0)
721 {
722 res =
723 cli_command_path (argc, argv, optind, fs, GET_FS_OPS_OFFSET (delete));
724 }
725 else if (strcmp (op, "download") == 0 || strcmp (op, "dl") == 0)
726 {
727 res = cli_download (argc, argv, optind, fs);
728 }
729 else if (strcmp (op, "upload") == 0 || strcmp (op, "ul") == 0)
730 {
731 res = cli_upload (argc, argv, optind, fs);
732 }
733 else if (strcmp (op, "cl") == 0)
734 {
735 res = cli_command_path (argc, argv, optind, fs,
736 GET_FS_OPS_OFFSET (clear));
737 }
738 else if (strcmp (op, "cp") == 0)
739 {
740 res = cli_command_src_dst (argc, argv, optind, fs,
741 GET_FS_OPS_OFFSET (copy));
742 }
743 else if (strcmp (op, "sw") == 0)
744 {
745 res = cli_command_src_dst (argc, argv, optind, fs,
746 GET_FS_OPS_OFFSET (swap));
747 }
748 else if (strcmp (op, "mv") == 0)
749 {
750 res = cli_command_src_dst (argc, argv, optind, fs,
751 GET_FS_OPS_OFFSET (move));
752 }
753 else
754 {
755 error_print ("Command '%s' not recognized\n", command);
756 res = EXIT_FAILURE;
757 }
758
759 end:
543760 if (connector_check (&connector))
544761 {
545762 connector_destroy (&connector);
546763 }
764
765 usleep (REST_TIME * 2);
547766 return res;
548767 }
1919
2020 #include "../config.h"
2121 #include <limits.h>
22 #include <locale.h>
2223 #include <gtk/gtk.h>
23 #include <unistd.h>
24 #include "connector.h"
25 #include <sys/stat.h>
26 #include <sys/types.h>
2724 #include <glib-unix.h>
2825 #include <glib/gi18n.h>
2926 #include <glib/gprintf.h>
3027 #define _GNU_SOURCE
3128 #include <getopt.h>
29 #include "connector.h"
3230 #include "browser.h"
3331 #include "audio.h"
3432 #include "sample.h"
3533 #include "utils.h"
3634 #include "notifier.h"
35 #include "local.h"
36 #include "preferences.h"
3737
3838 #define MAX_DRAW_X 10000
39 #define SIZE_LABEL_LEN 16
40
41 #define DEVICES_LIST_STORE_CARD_FIELD 0
42 #define DEVICES_LIST_STORE_NAME_FIELD 1
43
44 #define TASK_LIST_STORE_STATUS_FIELD 0
45 #define TASK_LIST_STORE_TYPE_FIELD 1
46 #define TASK_LIST_STORE_SRC_FIELD 2
47 #define TASK_LIST_STORE_DST_FIELD 3
48 #define TASK_LIST_STORE_PROGRESS_FIELD 4
49 #define TASK_LIST_STORE_STATUS_HUMAN_FIELD 5
50 #define TASK_LIST_STORE_TYPE_HUMAN_FIELD 6
5139
5240 #define DUMP_TIMEOUT 2000
53
54 #define UP_BUTTON_DND_TIMEOUT 1000
55
56 static gpointer elektroid_upload_task (gpointer);
57 static gpointer elektroid_download_task (gpointer);
58 static void elektroid_update_progress (gdouble);
59 static gboolean elektroid_load_local_dir (gpointer);
60
61 static struct option options[] = {
62 {"local-directory", 1, NULL, 'l'},
63 {"verbose", 0, NULL, 'v'},
64 {"help", 0, NULL, 'h'},
65 {NULL, 0, NULL, 0}
41 #define DND_TIMEOUT 1000
42
43 #define TEXT_URI_LIST_STD "text/uri-list"
44 #define TEXT_URI_LIST_ELEKTROID "text/uri-list-elektroid"
45
46 #define GUI_FSS (FS_SAMPLES | FS_RAW_PRESETS | FS_DATA_PRJ | FS_DATA_SND)
47
48 #define MSG_WARN_SAME_SRC_DST "Same source and destination path. Skipping...\n"
49
50 enum device_list_store_columns
51 {
52 DEVICES_LIST_STORE_CARD_FIELD,
53 DEVICES_LIST_STORE_NAME_FIELD
54 };
55
56 enum task_list_store_columns
57 {
58 TASK_LIST_STORE_STATUS_FIELD,
59 TASK_LIST_STORE_TYPE_FIELD,
60 TASK_LIST_STORE_SRC_FIELD,
61 TASK_LIST_STORE_DST_FIELD,
62 TASK_LIST_STORE_PROGRESS_FIELD,
63 TASK_LIST_STORE_STATUS_HUMAN_FIELD,
64 TASK_LIST_STORE_TYPE_HUMAN_FIELD,
65 TASK_LIST_STORE_REMOTE_FS_ID_FIELD,
66 TASK_LIST_STORE_REMOTE_FS_ICON_FIELD,
67 };
68
69 enum fs_list_store_columns
70 {
71 FS_LIST_STORE_ID_FIELD,
72 FS_LIST_STORE_ICON_FIELD,
73 FS_LIST_STORE_NAME_FIELD
74 };
75
76 enum
77 {
78 TARGET_STRING,
6679 };
6780
6881 enum elektroid_task_type
8093 CANCELED
8194 };
8295
83 struct elektroid_sample_transfer
84 {
85 struct connector_sample_transfer transfer;
96 struct elektroid_transfer
97 {
98 struct job_control control;
8699 gchar *src; //Contains a path to a file
87 gchar *dst; //Contains a path to a dir
100 gchar *dst; //Contains a path to a file
88101 enum elektroid_task_status status; //Contains the final status
102 const struct fs_operations *fs_ops; //Contains the fs_operations to use in this transfer
89103 };
90104
91 struct elektroid_sysex_transfer
92 {
93 struct connector_sysex_transfer transfer;
94 GByteArray *data;
105 struct elektroid_add_upload_task_data
106 {
107 struct item_iterator iter;
108 gint32 index;
95109 };
96110
97 #define TEXT_URI_LIST_STD "text/uri-list"
98 #define TEXT_URI_LIST_ELEKTROID "text/uri-list-elektroid"
99
100 enum
101 {
102 TARGET_STRING,
111 typedef int (*connector_send_raw) (struct connector *,
112 struct connector_sysex_transfer *);
113
114 static gpointer elektroid_upload_task (gpointer);
115 static gpointer elektroid_download_task (gpointer);
116 static void elektroid_update_progress (gdouble);
117
118 static const struct option ELEKTROID_OPTIONS[] = {
119 {"local-directory", 1, NULL, 'l'},
120 {"verbose", 0, NULL, 'v'},
121 {"help", 0, NULL, 'h'},
122 {NULL, 0, NULL, 0}
103123 };
124
125 static const gchar *ELEKTROID_FS_ICONS[] = {
126 FILE_ICON_WAVE, FILE_ICON_DATA, FILE_ICON_SND, FILE_ICON_DATA,
127 FILE_ICON_PRJ, FILE_ICON_SND
128 };
129
130 static gchar *ELEKTROID_AUDIO_LOCAL_EXTS[] =
131 { "wav", "ogg", "aiff", "flac", NULL };
104132
105133 static GtkTargetEntry TARGET_ENTRIES_LOCAL_DST[] = {
106134 {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET,
158186
159187 static struct audio audio;
160188 static struct connector connector;
161 static gboolean autoplay;
189 static struct preferences preferences;
162190
163191 static GThread *load_thread = NULL;
164192 static GThread *task_thread = NULL;
165193 static GThread *sysex_thread = NULL;
166 static struct elektroid_sample_transfer sample_transfer;
167 static struct elektroid_sysex_transfer sysex_transfer;
194 static struct elektroid_transfer transfer;
195 static struct connector_sysex_transfer sysex_transfer;
168196
169197 static GThread *notifier_thread = NULL;
170198 struct notifier notifier;
188216 static GtkListStore *devices_list_store;
189217 static GtkComboBox *devices_combo;
190218 static GtkWidget *upload_menuitem;
219 static GtkWidget *local_audio_box;
191220 static GtkWidget *local_play_menuitem;
192221 static GtkWidget *local_open_menuitem;
193222 static GtkWidget *local_show_menuitem;
204233 static GtkWidget *cancel_task_button;
205234 static GtkWidget *remove_tasks_button;
206235 static GtkWidget *clear_tasks_button;
236 static GtkListStore *fs_list_store;
237 static GtkComboBox *fs_combo;
238 static GtkTreeViewColumn *remote_tree_view_index_column;
239
240 static const gchar *
241 elektroid_get_fs_name (enum connector_fs fs)
242 {
243 switch (fs)
244 {
245 case FS_SAMPLES:
246 return _("Samples");
247 case FS_RAW_PRESETS:
248 return _("Presets");
249 case FS_DATA_PRJ:
250 return _("Projects");
251 case FS_DATA_SND:
252 return _("Sounds");
253 default:
254 return _("Undefined");
255 }
256 }
257
258 static void
259 elektroid_set_file_extensions_for_fs (gchar ** extensions[],
260 enum connector_fs sel_fs)
261 {
262 const struct fs_operations *ops;
263
264 if (*extensions != NULL && *extensions != ELEKTROID_AUDIO_LOCAL_EXTS)
265 {
266 g_free ((*extensions)[0]);
267 g_free (*extensions);
268 }
269 if (sel_fs == FS_SAMPLES)
270 {
271 *extensions = ELEKTROID_AUDIO_LOCAL_EXTS;
272 }
273 else
274 {
275 ops = connector_get_fs_operations (sel_fs);
276 *extensions = malloc (sizeof (gchar *) * 2);
277 (*extensions)[0] = connector_get_full_ext (connector.device_desc, ops);
278 (*extensions)[1] = NULL;
279 }
280 }
281
282 static const gchar *
283 elektroid_get_inventory_icon_for_fs (enum connector_fs sel_fs)
284 {
285 const gchar *icon = FILE_ICON_DATA;
286
287 for (int fs = FS_SAMPLES, i = 0; fs <= FS_DATA_SND; fs <<= 1, i++)
288 {
289 if (GUI_FSS & fs && sel_fs == fs)
290 {
291 icon = ELEKTROID_FS_ICONS[i];
292 break;
293 }
294 }
295 return icon;
296 }
207297
208298 static void
209299 show_error_msg (const char *format, ...)
217307 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
218308 GTK_DIALOG_DESTROY_WITH_PARENT |
219309 GTK_DIALOG_MODAL,
220 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, msg);
310 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s",
311 msg);
221312 gtk_dialog_run (GTK_DIALOG (dialog));
222313 gtk_widget_destroy (dialog);
223314 g_free (msg);
315 va_end (args);
224316 }
225317
226318 static void
233325
234326 debug_print (1, "Loading devices...\n");
235327
328 gtk_list_store_clear (fs_list_store);
236329 gtk_list_store_clear (devices_list_store);
237330
238331 for (i = 0; i < devices->len; i++)
250343 device_index = auto_select && i == 1 ? 0 : -1;
251344 debug_print (1, "Selecting device %d...\n", device_index);
252345 gtk_combo_box_set_active (devices_combo, device_index);
346
347 if (device_index == -1)
348 {
349 local_browser.file_icon =
350 elektroid_get_inventory_icon_for_fs (FS_SAMPLES);
351 elektroid_set_file_extensions_for_fs (&local_browser.extensions,
352 FS_SAMPLES);
353
354 gtk_widget_set_visible (local_audio_box, TRUE);
355 gtk_tree_view_column_set_visible (remote_tree_view_index_column, FALSE);
356
357 browser_load_dir (&local_browser);
358 }
253359 }
254360
255361 static void
258364 gchar *status;
259365 gchar *statfss_str;
260366 gint res;
261 enum connector_fs_type fs;
262 struct connector_statfs statfs;
367 enum connector_storage storage;
368 struct connector_storage_stats statfs;
263369 GString *statfss;
264370
265371 gtk_statusbar_pop (status_bar, 0);
268374 {
269375 statfss = g_string_new (NULL);
270376
271 if (connector.device_desc->capabilities & CAP_SAMPLE)
272 {
273 for (fs = FS_PLUS_DRIVE; fs <= FS_RAM; fs++)
377 for (storage = STORAGE_PLUS_DRIVE; storage <= STORAGE_RAM;
378 storage <<= 1)
379 {
380 if (connector.device_desc->storages & storage)
274381 {
275 res = connector_statfs (&connector, fs, &statfs);
382 res =
383 connector_get_storage_stats (&connector, storage, &statfs);
276384 if (!res)
277385 {
278386 g_string_append_printf (statfss, " %s %.2f%%",
279387 statfs.name,
280 connector_statfs_use_percent
388 connector_get_storage_stats_percent
281389 (&statfs));
282390 }
283391 }
299407 static gboolean
300408 elektroid_get_next_queued_task (GtkTreeIter * iter,
301409 enum elektroid_task_type *type,
302 gchar ** src, gchar ** dst)
410 gchar ** src, gchar ** dst, gint * fs)
303411 {
304412 enum elektroid_task_status status;
305413 gboolean found = FALSE;
314422 TASK_LIST_STORE_STATUS_FIELD, &status,
315423 TASK_LIST_STORE_TYPE_FIELD, type,
316424 TASK_LIST_STORE_SRC_FIELD, src,
317 TASK_LIST_STORE_DST_FIELD, dst, -1);
425 TASK_LIST_STORE_DST_FIELD, dst,
426 TASK_LIST_STORE_REMOTE_FS_ID_FIELD, fs, -1);
318427 }
319428 else
320429 {
340449 GtkListStore *list_store;
341450 GtkTreeIter iter;
342451 gboolean connected = connector_check (&connector);
343 gboolean queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL);
452 gboolean queued =
453 elektroid_get_next_queued_task (&iter, NULL, NULL, NULL, NULL);
344454
345455 gtk_widget_set_sensitive (remote_box, connected);
346456 gtk_widget_set_sensitive (rx_sysex_button, connected && !queued);
400510 elektroid_cancel_running_sysex (GtkDialog * dialog, gint response_id,
401511 gpointer data)
402512 {
403 g_mutex_lock (&sysex_transfer.transfer.mutex);
404 sysex_transfer.transfer.active = FALSE;
405 g_mutex_unlock (&sysex_transfer.transfer.mutex);
513 g_mutex_lock (&sysex_transfer.mutex);
514 sysex_transfer.active = FALSE;
515 g_mutex_unlock (&sysex_transfer.mutex);
406516 }
407517
408518 static void
426536 gboolean active;
427537 enum connector_sysex_transfer_status status;
428538
429 g_mutex_lock (&sysex_transfer.transfer.mutex);
430 status = sysex_transfer.transfer.status;
431 g_mutex_unlock (&sysex_transfer.transfer.mutex);
539 g_mutex_lock (&sysex_transfer.mutex);
540 status = sysex_transfer.status;
541 g_mutex_unlock (&sysex_transfer.mutex);
432542
433543 switch (status)
434544 {
448558 }
449559 gtk_label_set_text (GTK_LABEL (progress_label), text);
450560
451 g_mutex_lock (&sysex_transfer.transfer.mutex);
452 active = sysex_transfer.transfer.active;
453 g_mutex_unlock (&sysex_transfer.transfer.mutex);
561 g_mutex_lock (&sysex_transfer.mutex);
562 active = sysex_transfer.active;
563 g_mutex_unlock (&sysex_transfer.mutex);
454564
455565 return active;
456566 }
458568 static gpointer
459569 elektroid_rx_sysex_thread (gpointer data)
460570 {
571 gint *res = malloc (sizeof (gint));
461572 gchar *text;
462 GByteArray *msg;
463
464 sysex_transfer.transfer.status = WAITING;
465 sysex_transfer.transfer.active = TRUE;
466 sysex_transfer.transfer.timeout = DUMP_TIMEOUT;
467 sysex_transfer.transfer.batch = TRUE;
573
574 sysex_transfer.status = WAITING;
575 sysex_transfer.active = TRUE;
576 sysex_transfer.timeout = DUMP_TIMEOUT;
577 sysex_transfer.batch = TRUE;
468578
469579 g_timeout_add (100, elektroid_update_sysex_progress, NULL);
470580
471581 connector_rx_drain (&connector);
472 msg = connector_rx_sysex (&connector, &sysex_transfer.transfer);
473 if (msg)
474 {
475 text = debug_get_hex_msg (msg);
476 debug_print (1, "SysEx message received (%d): %s\n", msg->len, text);
582 *res = connector_rx_sysex (&connector, &sysex_transfer);
583 if (!*res)
584 {
585 text = debug_get_hex_msg (sysex_transfer.raw);
586 debug_print (1, "SysEx message received (%d): %s\n",
587 sysex_transfer.raw->len, text);
477588 free (text);
478589 }
479590
480591 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_ACCEPT);
481592
482 return msg;
593 return res;
483594 }
484595
485596 static gboolean
498609 GtkWidget *dialog;
499610 GtkFileChooser *chooser;
500611 GtkFileFilter *filter;
501 gint res;
612 gint dres;
502613 gchar *filename;
503614 gchar *filename_w_ext;
504615 const gchar *ext;
505 FILE *file;
506 GByteArray *sysex_data;
616 gint *res;
507617 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
508618
509619 g_idle_add (elektroid_start_rx_thread, NULL);
510620
511621 gtk_window_set_title (GTK_WINDOW (progress_dialog), _("Receive SysEx"));
512 res = gtk_dialog_run (GTK_DIALOG (progress_dialog));
513 sysex_transfer.transfer.active = FALSE;
622 dres = gtk_dialog_run (GTK_DIALOG (progress_dialog));
623 sysex_transfer.active = FALSE;
514624 gtk_widget_hide (GTK_WIDGET (progress_dialog));
515625
516 sysex_data = elektroid_join_sysex_thread ();
517
518 if (res != GTK_RESPONSE_ACCEPT)
519 {
520 if (sysex_data)
521 {
522 g_byte_array_free (sysex_data, TRUE);
523 }
626 res = elektroid_join_sysex_thread ();
627
628 if (dres != GTK_RESPONSE_ACCEPT)
629 {
630 if (!*res)
631 {
632 g_byte_array_free (sysex_transfer.raw, TRUE);
633 }
634 g_free (res);
524635 return;
525636 }
526637
527 if (!sysex_data)
638 if (*res)
528639 {
529640 elektroid_check_connector ();
641 g_free (res);
530642 return;
531643 }
532644
575687
576688 if (filename != NULL)
577689 {
578 debug_print (1, "Saving SysEx file...\n");
579 file = fopen (filename, "w");
580 fwrite (sysex_data->data, sysex_data->len, 1, file);
581 g_byte_array_free (sysex_data, TRUE);
582 fclose (file);
690 *res = save_file (filename, sysex_transfer.raw, NULL);
691 if (*res)
692 {
693 show_error_msg (_("Error while saving “%s”: %s."),
694 filename, g_strerror (*res));
695 }
696 g_byte_array_free (sysex_transfer.raw, TRUE);
697 g_free (res);
583698 g_free (filename);
584699 }
585700
590705 elektroid_tx_sysex_thread (gpointer data)
591706 {
592707 gchar *text;
593 gint *response = malloc (sizeof (gint));
594
595 sysex_transfer.transfer.active = TRUE;
596 sysex_transfer.transfer.timeout = SYSEX_TIMEOUT;
708 gint *res = malloc (sizeof (gint));
709 connector_send_raw f = data;
710
711 sysex_transfer.active = TRUE;
712 sysex_transfer.timeout = SYSEX_TIMEOUT;
597713
598714 g_timeout_add (100, elektroid_update_sysex_progress, NULL);
599715
600 *response =
601 connector_tx_sysex (&connector, sysex_transfer.data,
602 &sysex_transfer.transfer);
603 if (*response >= 0)
604 {
605 text = debug_get_hex_msg (sysex_transfer.data);
716 *res = f (&connector, &sysex_transfer);
717 if (!*res)
718 {
719 text = debug_get_hex_msg (sysex_transfer.raw);
606720 debug_print (1, "SysEx message sent (%d): %s\n",
607 sysex_transfer.data->len, text);
721 sysex_transfer.raw->len, text);
608722 free (text);
609723 }
610724
611725 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_CANCEL);
612726
613 return response;
614 }
615
616 static gboolean
617 elektroid_start_tx_thread (gpointer data)
618 {
619 debug_print (1, "Creating tx SysEx thread...\n");
620 sysex_thread = g_thread_new ("sysex_thread", data, NULL);
621
622 return FALSE;
623 }
624
625 static void
626 elektroid_tx_sysex_common (GThreadFunc tx_function)
727 return res;
728 }
729
730 static void
731 elektroid_tx_sysex_common (connector_send_raw f)
627732 {
628733 GtkWidget *dialog;
629734 GtkFileChooser *chooser;
630735 GtkFileFilter *filter;
631 gint res;
736 gint res, lres;
632737 char *filename;
633 FILE *file;
634 long size;
635738 gint *response;
636739 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
637740
655758 filename = gtk_file_chooser_get_filename (chooser);
656759 gtk_widget_destroy (dialog);
657760 debug_print (1, "Opening SysEx file...\n");
658 file = fopen (filename, "rb");
659 g_free (filename);
660 fseek (file, 0, SEEK_END);
661 size = ftell (file);
662 rewind (file);
663
664 sysex_transfer.data = g_byte_array_new ();
665 g_byte_array_set_size (sysex_transfer.data, size);
666 fread (sysex_transfer.data->data, size, 1, file);
667 fclose (file);
668
669 g_idle_add (elektroid_start_tx_thread, tx_function);
670
671 gtk_window_set_title (GTK_WINDOW (progress_dialog), _("Send SysEx"));
672 res = gtk_dialog_run (GTK_DIALOG (progress_dialog));
673
674 g_mutex_lock (&sysex_transfer.transfer.mutex);
675 sysex_transfer.transfer.active = FALSE;
676 g_mutex_unlock (&sysex_transfer.transfer.mutex);
677
678 gtk_widget_hide (GTK_WIDGET (progress_dialog));
679
680 response = elektroid_join_sysex_thread ();
681 g_byte_array_free (sysex_transfer.data, TRUE);
761
762 sysex_transfer.raw = g_byte_array_new ();
763
764 lres = load_file (filename, sysex_transfer.raw, NULL);
765 if (lres)
766 {
767 show_error_msg (_("Error while loading “%s”: %s."),
768 filename, g_strerror (lres));
769 response = NULL;
770 }
771 else
772 {
773 sysex_thread =
774 g_thread_new ("sysex_thread", elektroid_tx_sysex_thread, f);
775
776 gtk_window_set_title (GTK_WINDOW (progress_dialog),
777 _("Send SysEx"));
778 res = gtk_dialog_run (GTK_DIALOG (progress_dialog));
779
780 g_mutex_lock (&sysex_transfer.mutex);
781 sysex_transfer.active = FALSE;
782 g_mutex_unlock (&sysex_transfer.mutex);
783
784 gtk_widget_hide (GTK_WIDGET (progress_dialog));
785
786 response = elektroid_join_sysex_thread ();
787 }
788
789 g_byte_array_free (sysex_transfer.raw, TRUE);
790
682791
683792 if (*response < 0)
684793 {
696805 static void
697806 elektroid_tx_sysex (GtkWidget * object, gpointer data)
698807 {
699 elektroid_tx_sysex_common (elektroid_tx_sysex_thread);
700 }
701
702 static gpointer
703 elektroid_os_upgrade_thread (gpointer data)
704 {
705 gint *response = malloc (sizeof (gint));
706
707 sysex_transfer.transfer.active = TRUE;
708 sysex_transfer.transfer.timeout = SYSEX_TIMEOUT;
709
710 g_timeout_add (100, elektroid_update_sysex_progress, NULL);
711
712 *response =
713 connector_upgrade_os (&connector, sysex_transfer.data,
714 &sysex_transfer.transfer);
715
716 gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_CANCEL);
717
718 return response;
808 elektroid_tx_sysex_common (connector_tx_sysex);
719809 }
720810
721811 static void
722812 elektroid_upgrade_os (GtkWidget * object, gpointer data)
723813 {
724 elektroid_tx_sysex_common (elektroid_os_upgrade_thread);
814 elektroid_tx_sysex_common (connector_upgrade_os);
725815 connector_destroy (&connector);
726816 elektroid_check_connector ();
727817 }
746836 {
747837 gboolean ready_to_play;
748838
749 g_mutex_lock (&audio.mutex);
750 ready_to_play = audio.sample->len >= LOAD_BUFFER_LEN
751 || (!audio.load_active && audio.sample->len > 0);
752 g_mutex_unlock (&audio.mutex);
839 g_mutex_lock (&audio.control.mutex);
840 ready_to_play = audio.frames >= LOAD_BUFFER_LEN || (!audio.control.active
841 && audio.frames > 0);
842 g_mutex_unlock (&audio.control.mutex);
753843
754844 if (ready_to_play)
755845 {
757847 {
758848 elektroid_controls_set_sensitive (TRUE);
759849 }
760 if (autoplay)
850 if (preferences.autoplay)
761851 {
762852 audio_play (&audio);
763853 }
772862 struct browser *browser)
773863 {
774864 GtkTreeIter iter;
775 gchar *name;
776 gchar *icon;
777865 gchar *path;
778 gchar type;
866 gchar *id_path;
779867 gint err;
868 struct item *item;
780869
781870 gtk_tree_model_get_iter (model, &iter, tree_path);
782 browser_get_item_info (model, &iter, &icon, &name, NULL);
783 type = get_type_from_inventory_icon (icon);
784
785 path = chain_path (browser->dir, name);
786 debug_print (1, "Deleting %s...\n", path);
787
788 err = browser->delete (path, type);
789 if (err < 0)
871 item = browser_get_item (model, &iter);
872 path = browser_get_item_path (browser, item);
873 id_path = browser_get_item_id_path (browser, item);
874
875 debug_print (1, "Deleting %s...\n", id_path);
876 err = browser->fs_ops->delete (id_path, browser->data);
877 if (err)
790878 {
791879 show_error_msg (_("Error while deleting “%s”: %s."),
792 path, g_strerror (errno));
880 path, g_strerror (err));
793881 }
794882 else
795883 {
796884 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
797885 }
798886
799 free (path);
800 g_free (icon);
801 g_free (name);
887 g_free (path);
888 g_free (id_path);
889 browser_free_item (item);
802890 }
803891
804892 static void
805893 elektroid_delete_files (GtkWidget * object, gpointer data)
806894 {
807895 GtkTreeRowReference *reference;
808 GList *item;
896 GList *list;
809897 GtkTreePath *tree_path;
810898 GtkTreeSelection *selection;
811899 GtkTreeModel *model;
837925 tree_path_list = gtk_tree_selection_get_selected_rows (selection, &model);
838926 ref_list = NULL;
839927
840 for (item = tree_path_list; item != NULL; item = g_list_next (item))
841 {
842 reference = gtk_tree_row_reference_new (model, item->data);
928 for (list = tree_path_list; list != NULL; list = g_list_next (list))
929 {
930 reference = gtk_tree_row_reference_new (model, list->data);
843931 ref_list = g_list_append (ref_list, reference);
844932 }
845933 g_list_free_full (tree_path_list, (GDestroyNotify) gtk_tree_path_free);
846934
847 for (item = ref_list; item != NULL; item = g_list_next (item))
848 {
849 tree_path = gtk_tree_row_reference_get_path (item->data);
935 for (list = ref_list; list != NULL; list = g_list_next (list))
936 {
937 tree_path = gtk_tree_row_reference_get_path (list->data);
850938 elektroid_delete_file (model, tree_path, browser);
851939 }
852940 g_list_free_full (ref_list, (GDestroyNotify) gtk_tree_row_reference_free);
853941
854 browser->load_dir (NULL);
942 browser_load_dir (browser);
855943 }
856944
857945 static void
858946 elektroid_rename_item (GtkWidget * object, gpointer data)
859947 {
860 char *old_name;
861948 char *old_path;
862949 char *new_path;
863950 int result;
864951 gint err;
865952 GtkTreeIter iter;
953 struct item *item;
866954 struct browser *browser = data;
867955 GtkTreeModel *model =
868956 GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view));
869957
870958 browser_set_selected_row_iter (browser, &iter);
871 browser_get_item_info (model, &iter, NULL, &old_name, NULL);
872
873 old_path = chain_path (browser->dir, old_name);
874
875 gtk_entry_set_text (name_dialog_entry, old_name);
959 item = browser_get_item (model, &iter);
960 old_path = browser_get_item_id_path (browser, item);
961
962 gtk_entry_set_text (name_dialog_entry, item->name);
876963 gtk_widget_grab_focus (GTK_WIDGET (name_dialog_entry));
877964 gtk_widget_set_sensitive (name_dialog_accept_button, FALSE);
878965
890977 new_path =
891978 chain_path (browser->dir, gtk_entry_get_text (name_dialog_entry));
892979
893 err = browser->rename (old_path, new_path);
894
895 if (err < 0)
980 err = browser->fs_ops->move (old_path, new_path, &connector);
981
982 if (err)
896983 {
897984 show_error_msg (_("Error while renaming to “%s”: %s."),
898 new_path, g_strerror (errno));
985 new_path, g_strerror (err));
899986 }
900987 else
901988 {
902 browser->load_dir (NULL);
989 browser_load_dir (browser);
903990 }
904991
905992 free (new_path);
906993 }
907994 }
908995
909 free (old_name);
910 free (old_path);
996 browser_free_item (item);
997 g_free (old_path);
911998 gtk_widget_hide (GTK_WIDGET (name_dialog));
912999 }
9131000
9191006 GtkTreeSelection *selection;
9201007 GtkTreeModel *model;
9211008 GList *tree_path_list;
922 GList *item;
1009 GList *list;
9231010 gchar *uri;
924 gchar *item_name;
925 gchar *full_path;
1011 gchar *path;
1012 struct item *item;
9261013 struct browser *browser = data;
9271014
9281015 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
9301017 tree_path_list = gtk_tree_selection_get_selected_rows (selection, &model);
9311018
9321019 browser->dnd_data = g_string_new ("");
933 for (item = tree_path_list; item != NULL; item = g_list_next (item))
934 {
935 gtk_tree_model_get_iter (model, &iter, item->data);
936 browser_get_item_info (model, &iter, NULL, &item_name, NULL);
937 full_path = chain_path (browser->dir, item_name);
938 free (item_name);
1020 for (list = tree_path_list; list != NULL; list = g_list_next (list))
1021 {
1022 gtk_tree_model_get_iter (model, &iter, list->data);
1023 item = browser_get_item (model, &iter);
1024 path = browser_get_item_id_path (browser, item);
1025 browser_free_item (item);
9391026 if (widget == GTK_WIDGET (local_browser.view))
9401027 {
941 uri = g_filename_to_uri (full_path, NULL, NULL);
1028 uri = g_filename_to_uri (path, NULL, NULL);
9421029 }
9431030 else if (widget == GTK_WIDGET (remote_browser.view))
9441031 {
945 uri = chain_path ("file://", &full_path[1]);
1032 uri = chain_path ("file://", &path[1]);
9461033 }
9471034 else
9481035 {
9491036 continue;
9501037 }
951 g_free (full_path);
1038 g_free (path);
9521039 g_string_append (browser->dnd_data, uri);
9531040 g_free (uri);
9541041 g_string_append (browser->dnd_data, "\n");
10441131 if (!path)
10451132 {
10461133 gtk_tree_selection_unselect_all (selection);
1134 gtk_menu_popup_at_pointer (browser->menu, (GdkEvent *) event);
10471135 return FALSE;
10481136 }
10491137
11211209 static gpointer
11221210 elektroid_load_sample (gpointer path)
11231211 {
1124 g_mutex_lock (&audio.mutex);
1125 audio.load_active = TRUE;
1126 g_mutex_unlock (&audio.mutex);
1127
1128 sample_load (audio.sample, &audio.mutex, &audio.frames, path,
1129 &audio.load_active, elektroid_redraw_sample);
1130
1131 g_mutex_lock (&audio.mutex);
1132 audio.load_active = FALSE;
1133 g_mutex_unlock (&audio.mutex);
1212 struct sample_loop_data *sample_loop_data;
1213 g_mutex_lock (&audio.control.mutex);
1214 audio.control.active = TRUE;
1215 g_mutex_unlock (&audio.control.mutex);
1216
1217 if (sample_load_with_frames
1218 (path, audio.sample, &audio.control, &audio.frames) >= 0)
1219 {
1220 sample_loop_data = (struct sample_loop_data *) audio.control.data;
1221 debug_print (1, "Loop start at %d, loop end at %d\n",
1222 sample_loop_data->start, sample_loop_data->end);
1223 g_free (audio.control.data);
1224 }
1225
1226 g_mutex_lock (&audio.control.mutex);
1227 audio.control.active = FALSE;
1228 g_mutex_unlock (&audio.control.mutex);
11341229
11351230 free (path);
11361231
11521247 {
11531248 debug_print (1, "Stopping load thread...\n");
11541249
1155 g_mutex_lock (&audio.mutex);
1156 audio.load_active = FALSE;
1157 g_mutex_unlock (&audio.mutex);
1250 g_mutex_lock (&audio.control.mutex);
1251 audio.control.active = FALSE;
1252 g_mutex_unlock (&audio.control.mutex);
11581253
11591254 if (load_thread)
11601255 {
11791274 {
11801275 debug_print (1, "Stopping task thread...\n");
11811276
1182 g_mutex_lock (&sample_transfer.transfer.mutex);
1183 sample_transfer.transfer.active = FALSE;
1184 g_mutex_unlock (&sample_transfer.transfer.mutex);
1277 g_mutex_lock (&transfer.control.mutex);
1278 transfer.control.active = FALSE;
1279 g_mutex_unlock (&transfer.control.mutex);
11851280
11861281 elektroid_join_task_thread ();
11871282 }
11901285 elektroid_remote_check_selection (gpointer data)
11911286 {
11921287 gint count = browser_get_selected_items_count (&remote_browser);
1193
1194 gtk_widget_set_sensitive (remote_rename_menuitem, count == 1);
1195 gtk_widget_set_sensitive (remote_delete_menuitem, count > 0 ? TRUE : FALSE);
1196 gtk_widget_set_sensitive (download_menuitem, count > 0);
1288 gboolean dl_impl = remote_browser.fs_ops->download ? TRUE : FALSE;
1289 gboolean move_impl = remote_browser.fs_ops->move ? TRUE : FALSE;
1290 gboolean del_impl = remote_browser.fs_ops->delete ? TRUE : FALSE;
1291
1292 gtk_widget_set_sensitive (download_menuitem, count > 0 && dl_impl);
1293 gtk_widget_set_sensitive (remote_rename_menuitem, count == 1 && move_impl);
1294 gtk_widget_set_sensitive (remote_delete_menuitem, count > 0 && del_impl);
11971295
11981296 return FALSE;
11991297 }
12031301 {
12041302 GtkTreeIter iter;
12051303 gchar *sample_path;
1206 gchar *name;
1207 gchar *icon;
1208 gchar type;
12091304 GtkTreeModel *model;
1305 struct item *item = NULL;
12101306 gint count = browser_get_selected_items_count (&local_browser);
12111307
1212 audio_stop (&audio, TRUE);
1213 elektroid_stop_load_thread ();
1214 audio_reset_sample (&audio);
1215 gtk_widget_queue_draw (waveform_draw_area);
1216 elektroid_controls_set_sensitive (FALSE);
1217
1218 if (count == 1)
1308 if (count == 0)
1309 {
1310 audio.name[0] = 0;
1311 }
1312 else if (count == 1)
12191313 {
12201314 browser_set_selected_row_iter (&local_browser, &iter);
12211315 model = GTK_TREE_MODEL (gtk_tree_view_get_model (local_browser.view));
1222 browser_get_item_info (model, &iter, &icon, &name, NULL);
1223 type = get_type_from_inventory_icon (icon);
1224 if (type == ELEKTROID_FILE)
1225 {
1226 gtk_widget_set_sensitive (local_open_menuitem, TRUE);
1227 sample_path = chain_path (local_browser.dir, name);
1316 item = browser_get_item (model, &iter);
1317 if (!strcmp (audio.name, item->name))
1318 {
1319 goto end;
1320 }
1321 }
1322
1323 if (!remote_browser.fs_ops || remote_browser.fs_ops->fs == FS_SAMPLES)
1324 {
1325 audio_stop (&audio, TRUE);
1326 elektroid_stop_load_thread ();
1327 audio_reset_sample (&audio);
1328 gtk_widget_queue_draw (waveform_draw_area);
1329 elektroid_controls_set_sensitive (FALSE);
1330
1331 if (item && item->type == ELEKTROID_FILE
1332 && strcmp (item->name, audio.name))
1333 {
1334 sample_path = chain_path (local_browser.dir, item->name);
12281335 elektroid_start_load_thread (sample_path);
1229 }
1230 else
1231 {
1232 gtk_widget_set_sensitive (local_open_menuitem, FALSE);
1233 }
1234 g_free (icon);
1235 g_free (name);
1336 strcpy (audio.name, item->name);
1337 }
1338 gtk_widget_set_sensitive (local_open_menuitem, item
1339 && item->type == ELEKTROID_FILE);
1340 }
1341
1342 end:
1343 if (item)
1344 {
1345 browser_free_item (item);
12361346 }
12371347
12381348 gtk_widget_set_sensitive (local_show_menuitem, count <= 1);
12391349 gtk_widget_set_sensitive (local_rename_menuitem, count == 1);
12401350 gtk_widget_set_sensitive (local_delete_menuitem, count > 0);
1241 gtk_widget_set_sensitive (upload_menuitem, count > 0);
1351 gtk_widget_set_sensitive (upload_menuitem, count > 0
1352 && remote_browser.fs_ops
1353 && remote_browser.fs_ops->upload);
12421354
12431355 return FALSE;
12441356 }
12531365 double x_ratio, mid_y, value;
12541366 short *sample;
12551367
1256 g_mutex_lock (&audio.mutex);
1257
1258 if (audio.sample->len <= 0)
1259 {
1260 g_mutex_unlock (&audio.mutex);
1261 return FALSE;
1262 }
1368 g_mutex_lock (&audio.control.mutex);
12631369
12641370 context = gtk_widget_get_style_context (widget);
12651371 width = gtk_widget_get_allocated_width (widget);
12751381 for (i = 0; i < MAX_DRAW_X; i++)
12761382 {
12771383 x_sample = i * x_ratio;
1278 if (x_sample < audio.sample->len)
1384 if (x_sample < audio.sample->len >> 1)
12791385 {
12801386 x_widget = i * ((double) width) / MAX_DRAW_X;
12811387 value = mid_y - mid_y * (sample[x_sample] / (float) SHRT_MIN);
12851391 }
12861392 }
12871393
1288 g_mutex_unlock (&audio.mutex);
1394 g_mutex_unlock (&audio.control.mutex);
12891395
12901396 return FALSE;
12911397 }
12951401 {
12961402 GtkTreeIter iter;
12971403 GtkTreeModel *model;
1298 gchar *name;
12991404 gchar *uri;
13001405 GVariant *params, *result;
13011406 GVariantBuilder builder;
13021407 GFile *file;
13031408 GDBusProxy *proxy;
1409 struct item *item;
13041410 gchar *path = NULL;
13051411 gboolean done = FALSE;
13061412 gint count = browser_get_selected_items_count (&local_browser);
13131419 {
13141420 browser_set_selected_row_iter (&local_browser, &iter);
13151421 model = GTK_TREE_MODEL (gtk_tree_view_get_model (local_browser.view));
1316 browser_get_item_info (model, &iter, NULL, &name, NULL);
1317 path = chain_path (local_browser.dir, name);
1318 g_free (name);
1422 item = browser_get_item (model, &iter);
1423 path = chain_path (local_browser.dir, item->name);
1424 browser_free_item (item);
13191425 }
13201426 else
13211427 {
13691475 {
13701476 GtkTreeIter iter;
13711477 GtkTreeModel *model;
1372 gchar *name;
13731478 gchar *path;
13741479 gchar *uri;
13751480 GFile *file;
1481 struct item *item;
13761482
13771483 browser_set_selected_row_iter (&local_browser, &iter);
13781484 model = GTK_TREE_MODEL (gtk_tree_view_get_model (local_browser.view));
1379 browser_get_item_info (model, &iter, NULL, &name, NULL);
1380 path = chain_path (local_browser.dir, name);
1381 g_free (name);
1485 item = browser_get_item (model, &iter);
1486 path = chain_path (local_browser.dir, item->name);
1487 browser_free_item (item);
13821488
13831489 file = g_file_new_for_path (path);
13841490 g_free (path);
14101516 static gboolean
14111517 elektroid_autoplay_clicked (GtkWidget * object, gboolean state, gpointer data)
14121518 {
1413 autoplay = state;
1519 preferences.autoplay = state;
14141520 return FALSE;
14151521 }
14161522
14241530 elektroid_set_volume_callback (gdouble value)
14251531 {
14261532 gtk_scale_button_set_value (GTK_SCALE_BUTTON (volume_button), value);
1427 }
1428
1429 static void
1430 elektroid_add_dentry_item (GtkListStore * list_store,
1431 const gchar type, const gchar * name, ssize_t size)
1432 {
1433 const gchar *type_icon;
1434 char human_size[SIZE_LABEL_LEN];
1435
1436 type_icon = get_inventory_icon_from_type (type);
1437
1438 if (size > 0)
1439 {
1440 snprintf (human_size, SIZE_LABEL_LEN, "%.2f MiB",
1441 size / (1024.0 * 1024.0));
1442 }
1443 else
1444 {
1445 human_size[0] = 0;
1446 }
1447
1448 gtk_list_store_insert_with_values (list_store, NULL, -1,
1449 BROWSER_LIST_STORE_ICON_TYPE_FIELD,
1450 type_icon, BROWSER_LIST_STORE_NAME_FIELD,
1451 name, BROWSER_LIST_STORE_SIZE_FIELD,
1452 size,
1453 BROWSER_LIST_STORE_HUMAN_SIZE_FIELD,
1454 human_size, -1);
1455 }
1456
1457 static gboolean
1458 elektroid_load_remote_dir (gpointer data)
1459 {
1460 struct connector_dir_iterator *d_iter;
1461 GtkListStore *list_store =
1462 GTK_LIST_STORE (gtk_tree_view_get_model (remote_browser.view));
1463
1464 browser_reset (&remote_browser);
1465
1466 d_iter = connector_read_dir (&connector, remote_browser.dir);
1467 elektroid_check_connector ();
1468 if (!d_iter)
1469 {
1470 error_print ("Error while opening remote %s dir\n", remote_browser.dir);
1471 goto end;
1472 }
1473
1474 while (!connector_get_next_dentry (d_iter))
1475 {
1476 elektroid_add_dentry_item (list_store, d_iter->type,
1477 d_iter->dentry, d_iter->size);
1478 }
1479 connector_free_dir_iterator (d_iter);
1480
1481 end:
1482 gtk_tree_view_columns_autosize (remote_browser.view);
1483 return FALSE;
1484 }
1485
1486 static gint
1487 elektroid_valid_file (const gchar * name)
1488 {
1489 const gchar *ext = get_ext (name);
1490
1491 return (ext != NULL
1492 && (!strcasecmp (ext, "wav") || !strcasecmp (ext, "ogg")
1493 || !strcasecmp (ext, "aiff") || !strcasecmp (ext, "flac")));
1494 }
1495
1496 static gboolean
1497 elektroid_go_up_local_dir (gpointer data)
1498 {
1499 browser_go_up (NULL, &local_browser);
1500 return FALSE;
1501 }
1502
1503 static gboolean
1504 elektroid_load_local_dir (gpointer data)
1505 {
1506 DIR *dir;
1507 struct dirent *dirent;
1508 gchar type;
1509 struct stat st;
1510 ssize_t size;
1511 gchar *path;
1512 GtkListStore *list_store =
1513 GTK_LIST_STORE (gtk_tree_view_get_model (local_browser.view));
1514
1515 browser_reset (&local_browser);
1516
1517 if (!(dir = opendir (local_browser.dir)))
1518 {
1519 error_print ("Error while opening local %s dir\n", local_browser.dir);
1520 goto end;
1521 }
1522
1523 notifier_set_dir (&notifier, local_browser.dir);
1524
1525 while ((dirent = readdir (dir)) != NULL)
1526 {
1527 if (dirent->d_name[0] == '.')
1528 {
1529 continue;
1530 }
1531
1532 if (dirent->d_type == DT_DIR
1533 || (dirent->d_type == DT_REG
1534 && elektroid_valid_file (dirent->d_name)))
1535 {
1536 if (dirent->d_type == DT_DIR)
1537 {
1538 type = ELEKTROID_DIR;
1539 size = -1;
1540 }
1541 else
1542 {
1543 type = ELEKTROID_FILE;
1544 path = chain_path (local_browser.dir, dirent->d_name);
1545 if (stat (path, &st) == 0)
1546 {
1547 size = st.st_size;
1548 }
1549 else
1550 {
1551 size = -1;
1552 }
1553 free (path);
1554 }
1555 elektroid_add_dentry_item (list_store, type, dirent->d_name, size);
1556 }
1557 }
1558 closedir (dir);
1559
1560 end:
1561 gtk_tree_view_columns_autosize (local_browser.view);
1562 return FALSE;
1563 }
1564
1565 static gint
1566 elektroid_remote_mkdir (const gchar * name)
1567 {
1568 return connector_create_dir (&connector, name);
1569 }
1570
1571 static gint
1572 elektroid_local_mkdir (const gchar * name)
1573 {
1574 DIR *dir;
1575 gint error = 0;
1576 gchar *dup;
1577 gchar *parent;
1578
1579 dup = strdup (name);
1580 parent = dirname (dup);
1581
1582 dir = opendir (parent);
1583 if (dir)
1584 {
1585 closedir (dir);
1586 }
1587 else
1588 {
1589 error = elektroid_local_mkdir (parent);
1590 if (error)
1591 {
1592 goto cleanup;
1593 }
1594 }
1595
1596 if (mkdir (name, 0755) == 0 || errno == EEXIST)
1597 {
1598 error = 0;
1599 }
1600 else
1601 {
1602 error_print ("Error while creating dir %s\n", name);
1603 error = errno;
1604 }
1605
1606 cleanup:
1607 g_free (dup);
1608 return error;
16091533 }
16101534
16111535 static void
16341558 pathname =
16351559 chain_path (browser->dir, gtk_entry_get_text (name_dialog_entry));
16361560
1637 err = browser->mkdir (pathname);
1638
1639 if (err < 0)
1561 err = browser->fs_ops->mkdir (pathname, &connector);
1562
1563 if (err)
16401564 {
16411565 show_error_msg (_("Error while creating dir “%s”: %s."),
1642 pathname, g_strerror (errno));
1566 pathname, g_strerror (err));
16431567 }
16441568 else
16451569 {
1646 browser->load_dir (NULL);
1570 browser_load_dir (browser);
16471571 }
16481572
16491573 free (pathname);
16751599 else
16761600 {
16771601 gtk_widget_set_sensitive (name_dialog_accept_button, FALSE);
1678 }
1679 }
1680
1681 static gint
1682 elektroid_remote_rename (const gchar * old, const gchar * new)
1683 {
1684 debug_print (1, "Renaming remotely from %s to %s...\n", old, new);
1685 return connector_rename (&connector, old, new);
1686 }
1687
1688 static gint
1689 elektroid_local_rename (const gchar * old, const gchar * new)
1690 {
1691 debug_print (1, "Renaming locally from %s to %s...\n", old, new);
1692 return rename (old, new);
1693 }
1694
1695 static gint
1696 elektroid_remote_delete (const gchar * path, const char type)
1697 {
1698 struct connector_dir_iterator *d_iter;
1699 gchar *new_path;
1700
1701 if (type == ELEKTROID_DIR)
1702 {
1703 debug_print (1, "Deleting remote %s dir...\n", path);
1704 d_iter = connector_read_dir (&connector, path);
1705 elektroid_check_connector ();
1706 if (d_iter)
1707 {
1708 while (!connector_get_next_dentry (d_iter))
1709 {
1710 new_path = chain_path (path, d_iter->dentry);
1711 elektroid_remote_delete (new_path, d_iter->type);
1712 free (new_path);
1713 }
1714 connector_free_dir_iterator (d_iter);
1715 }
1716 else
1717 {
1718 error_print ("Error while opening remote %s dir\n", path);
1719 }
1720 return connector_delete_dir (&connector, path);
1721 }
1722 else
1723 {
1724 debug_print (1, "Deleting remote %s file...\n", path);
1725 return connector_delete_file (&connector, path);
1726 }
1727 }
1728
1729 static gint
1730 elektroid_local_delete (const gchar * path, const char type)
1731 {
1732 DIR *dir;
1733 struct dirent *dirent;
1734 gchar *new_path;
1735 gchar new_type;
1736
1737 if (type == ELEKTROID_DIR)
1738 {
1739 debug_print (1, "Deleting local %s dir...\n", path);
1740 dir = opendir (path);
1741 if (dir)
1742 {
1743 while ((dirent = readdir (dir)) != NULL)
1744 {
1745 if (strcmp (dirent->d_name, ".") == 0 ||
1746 strcmp (dirent->d_name, "..") == 0)
1747 {
1748 continue;
1749 }
1750 new_path = chain_path (path, dirent->d_name);
1751 new_type =
1752 dirent->d_type == DT_DIR ? ELEKTROID_DIR : ELEKTROID_FILE;
1753 elektroid_local_delete (new_path, new_type);
1754 free (new_path);
1755 }
1756 closedir (dir);
1757 }
1758 else
1759 {
1760 error_print ("Error while opening local %s dir\n", path);
1761 }
1762 return rmdir (path);
1763 }
1764 else
1765 {
1766 debug_print (1, "Deleting local %s file...\n", path);
1767 return unlink (path);
17681602 }
17691603 }
17701604
18311665 static void
18321666 elektroid_stop_running_task (GtkWidget * object, gpointer data)
18331667 {
1834 g_mutex_lock (&sample_transfer.transfer.mutex);
1835 sample_transfer.transfer.active = FALSE;
1836 g_mutex_unlock (&sample_transfer.transfer.mutex);
1668 g_mutex_lock (&transfer.control.mutex);
1669 transfer.control.active = FALSE;
1670 g_mutex_unlock (&transfer.control.mutex);
18371671 }
18381672
18391673 static gboolean
19651799 elektroid_complete_running_task (gpointer data)
19661800 {
19671801 GtkTreeIter iter;
1968 const gchar *status =
1969 elektroid_get_human_task_status (sample_transfer.status);
1802 const gchar *status = elektroid_get_human_task_status (transfer.status);
19701803
19711804 if (elektroid_get_running_task (&iter))
19721805 {
19731806 gtk_list_store_set (task_list_store, &iter,
19741807 TASK_LIST_STORE_STATUS_FIELD,
1975 sample_transfer.status,
1808 transfer.status,
19761809 TASK_LIST_STORE_STATUS_HUMAN_FIELD, status, -1);
19771810 elektroid_stop_running_task (NULL, NULL);
1978 g_free (sample_transfer.src);
1979 g_free (sample_transfer.dst);
1811 g_free (transfer.src);
1812 g_free (transfer.dst);
19801813
19811814 gtk_widget_set_sensitive (cancel_task_button, FALSE);
19821815 }
19951828 enum elektroid_task_type type;
19961829 gchar *src;
19971830 gchar *dst;
1831 gint fs;
19981832 GtkTreePath *path;
1999 gboolean sample_transfer_active;
2000 gboolean found = elektroid_get_next_queued_task (&iter, &type, &src, &dst);
1833 gboolean transfer_active;
1834 gboolean found =
1835 elektroid_get_next_queued_task (&iter, &type, &src, &dst, &fs);
20011836 const gchar *status_human = elektroid_get_human_task_status (RUNNING);
20021837
2003 g_mutex_lock (&sample_transfer.transfer.mutex);
2004 sample_transfer_active = sample_transfer.transfer.active;
2005 g_mutex_unlock (&sample_transfer.transfer.mutex);
2006
2007 if (!sample_transfer_active && found)
1838 g_mutex_lock (&transfer.control.mutex);
1839 transfer_active = transfer.control.active;
1840 g_mutex_unlock (&transfer.control.mutex);
1841
1842 if (!transfer_active && found)
20081843 {
20091844 gtk_list_store_set (task_list_store, &iter,
20101845 TASK_LIST_STORE_STATUS_FIELD, RUNNING,
20151850 gtk_tree_view_set_cursor (GTK_TREE_VIEW (task_tree_view), path, NULL,
20161851 FALSE);
20171852 gtk_tree_path_free (path);
2018 sample_transfer.transfer.active = TRUE;
2019 sample_transfer.src = src;
2020 sample_transfer.dst = dst;
2021 debug_print (1, "Running task type %d from %s to %s...\n", type,
2022 sample_transfer.src, sample_transfer.dst);
1853 transfer.control.active = TRUE;
1854 transfer.control.callback = elektroid_update_progress;
1855 transfer.src = src;
1856 transfer.dst = dst;
1857 transfer.fs_ops = connector_get_fs_operations (fs);
1858 debug_print (1, "Running task type %d from %s to %s (%s)...\n", type,
1859 transfer.src, transfer.dst, elektroid_get_fs_name (fs));
1860
20231861 if (type == UPLOAD)
20241862 {
20251863 task_thread =
20481886 static gpointer
20491887 elektroid_upload_task (gpointer data)
20501888 {
2051 char *basec;
2052 char *bname;
2053 char *remote_path;
2054 ssize_t frames;
2055 GArray *sample;
2056
2057 debug_print (1, "Local path: %s\n", sample_transfer.src);
2058
2059 basec = strdup (sample_transfer.src);
2060 bname = basename (basec);
2061 remove_ext (bname);
2062 remote_path = chain_path (sample_transfer.dst, bname);
2063 free (basec);
2064
2065 debug_print (1, "Remote path: %s\n", remote_path);
2066
2067 sample = g_array_new (FALSE, FALSE, sizeof (gshort));
2068
2069 frames = sample_load (sample, &sample_transfer.transfer.mutex, NULL,
2070 sample_transfer.src, &sample_transfer.transfer.active,
2071 NULL);
2072
2073 if (frames < 0)
2074 {
2075 error_print ("Error while reading sample\n");
2076 sample_transfer.status = COMPLETED_ERROR;
2077 goto complete_task;
2078 }
2079
2080 frames = connector_upload (&connector, sample, remote_path,
2081 &sample_transfer.transfer,
2082 elektroid_update_progress);
1889 gchar *dst_path;
1890 gchar *dst_dir;
1891 gint res;
1892 GByteArray *array;
1893
1894 debug_print (1, "Local path: %s\n", transfer.src);
1895 debug_print (1, "Remote path: %s\n", transfer.dst);
1896
1897 array = g_byte_array_new ();
1898
1899 res = transfer.fs_ops->load (transfer.src, array, &transfer.control);
1900 if (res)
1901 {
1902 error_print ("Error while loading file\n");
1903 transfer.status = COMPLETED_ERROR;
1904 goto end_cleanup;
1905 }
1906
1907 debug_print (1, "Writing from file %s (filesystem %s)...\n", transfer.src,
1908 elektroid_get_fs_name (transfer.fs_ops->fs));
1909
1910 res = transfer.fs_ops->upload (transfer.dst, array, &transfer.control,
1911 remote_browser.data);
1912 g_free (transfer.control.data);
1913 transfer.control.data = NULL;
20831914 g_idle_add (elektroid_check_connector_bg, NULL);
2084 free (remote_path);
2085
2086 if (frames < 0 && sample_transfer.transfer.active)
1915
1916 if (res && transfer.control.active)
20871917 {
20881918 error_print ("Error while uploading\n");
2089 sample_transfer.status = COMPLETED_ERROR;
1919 transfer.status = COMPLETED_ERROR;
20901920 }
20911921 else
20921922 {
2093 g_mutex_lock (&sample_transfer.transfer.mutex);
2094 if (sample_transfer.transfer.active)
2095 {
2096 sample_transfer.status = COMPLETED_OK;
1923 g_mutex_lock (&transfer.control.mutex);
1924 if (transfer.control.active)
1925 {
1926 transfer.status = COMPLETED_OK;
20971927 }
20981928 else
20991929 {
2100 sample_transfer.status = CANCELED;
2101 }
2102 g_mutex_unlock (&sample_transfer.transfer.mutex);
2103 }
2104
2105 g_array_free (sample, TRUE);
2106
2107 if (frames > 0)
2108 {
2109 if (strcmp (sample_transfer.dst, remote_browser.dir) == 0)
2110 {
2111 g_idle_add (remote_browser.load_dir, NULL);
2112 }
2113 }
2114
2115 complete_task:
1930 transfer.status = CANCELED;
1931 }
1932 g_mutex_unlock (&transfer.control.mutex);
1933 }
1934
1935 if (!res && transfer.fs_ops == remote_browser.fs_ops) //There is no need to refresh the local browser
1936 {
1937 dst_path = strdup (transfer.dst);
1938 dst_dir = dirname (dst_path);
1939 if (strcmp (dst_dir, remote_browser.dir) == 0)
1940 {
1941 g_idle_add (browser_load_dir, &remote_browser);
1942 }
1943 g_free (dst_path);
1944 }
1945
1946 end_cleanup:
1947 g_byte_array_free (array, TRUE);
21161948 g_idle_add (elektroid_complete_running_task, NULL);
21171949 g_idle_add (elektroid_run_next_task, NULL);
21181950
21211953
21221954 static void
21231955 elektroid_add_task (enum elektroid_task_type type, const char *src,
2124 const char *dst)
1956 const char *dst, gint remote_fs_id)
21251957 {
21261958 const gchar *status_human = elektroid_get_human_task_status (QUEUED);
21271959 const gchar *type_human = elektroid_get_human_task_type (type);
1960 const gchar *icon = elektroid_get_inventory_icon_for_fs (remote_fs_id);
1961
21281962
21291963 gtk_list_store_insert_with_values (task_list_store, NULL, -1,
21301964 TASK_LIST_STORE_STATUS_FIELD, QUEUED,
21351969 TASK_LIST_STORE_STATUS_HUMAN_FIELD,
21361970 status_human,
21371971 TASK_LIST_STORE_TYPE_HUMAN_FIELD,
2138 type_human, -1);
1972 type_human,
1973 TASK_LIST_STORE_REMOTE_FS_ID_FIELD,
1974 remote_fs_id,
1975 TASK_LIST_STORE_REMOTE_FS_ICON_FIELD,
1976 icon, -1);
21391977
21401978 gtk_widget_set_sensitive (remove_tasks_button, TRUE);
21411979 }
21421980
21431981 static void
2144 elektroid_add_upload_task_path (gchar * rel_path, gchar * src_dir,
2145 gchar * dst_dir)
2146 {
1982 elektroid_add_upload_task_path (const gchar * rel_path, const gchar * src_dir,
1983 const gchar * dst_dir,
1984 struct item_iterator *remote_dir_iter,
1985 gint32 * next_idx)
1986 {
1987 gint32 children_next_idx;
21471988 gchar *path;
2148 struct dirent *dirent;
21491989 gchar *dst_abs_dir;
1990 gchar *upload_path;
1991 struct item_iterator iter;
1992 struct item_iterator children_remote_item_iterator;
1993 gchar *dst_abs_path = chain_path (dst_dir, rel_path);
1994 gchar *src_abs_path = chain_path (src_dir, rel_path);
1995
1996 if (local_browser.fs_ops->readdir (&iter, src_abs_path, local_browser.data))
1997 {
1998 dst_abs_dir = dirname (dst_abs_path);
1999 upload_path =
2000 connector_get_upload_path (&connector, remote_dir_iter,
2001 remote_browser.fs_ops, dst_abs_dir,
2002 src_abs_path, next_idx);
2003 elektroid_add_task (UPLOAD, src_abs_path, upload_path,
2004 remote_browser.fs_ops->fs);
2005 goto cleanup_not_dir;
2006 }
2007
2008 if (remote_browser.fs_ops->mkdir)
2009 {
2010 if (remote_browser.fs_ops->mkdir (dst_abs_path, remote_browser.data))
2011 {
2012 error_print ("Error while creating remote %s dir\n", dst_abs_path);
2013 goto cleanup;
2014 }
2015
2016 if (!strchr (rel_path, '/'))
2017 {
2018 browser_load_dir (&remote_browser);
2019 }
2020 }
2021
2022 if (!remote_browser.fs_ops->readdir (&children_remote_item_iterator,
2023 dst_abs_path, remote_browser.data))
2024 {
2025 while (!next_item_iterator (&iter))
2026 {
2027 path = chain_path (rel_path, iter.item.name);
2028 elektroid_add_upload_task_path (path, src_dir, dst_dir,
2029 &children_remote_item_iterator,
2030 &children_next_idx);
2031 free (path);
2032 }
2033
2034 free_item_iterator (&children_remote_item_iterator);
2035 }
2036
2037
2038 cleanup:
2039 free_item_iterator (&iter);
2040 cleanup_not_dir:
2041 g_free (dst_abs_path);
2042 g_free (src_abs_path);
2043 }
2044
2045 static void
2046 elektroid_add_upload_task (GtkTreeModel * model,
2047 GtkTreePath * path,
2048 GtkTreeIter * iter, gpointer userdata)
2049 {
2050 struct item *item = browser_get_item (model, iter);
2051 struct elektroid_add_upload_task_data *data = userdata;
2052 elektroid_add_upload_task_path (item->name, local_browser.dir,
2053 remote_browser.dir, &data->iter,
2054 &data->index);
2055 browser_free_item (item);
2056 }
2057
2058 static void
2059 elektroid_add_upload_tasks (GtkWidget * object, gpointer userdata)
2060 {
2061 gboolean queued;
2062 GtkTreeIter iter;
2063 struct elektroid_add_upload_task_data data;
2064 GtkTreeSelection *selection =
2065 gtk_tree_view_get_selection (GTK_TREE_VIEW (local_browser.view));
2066
2067 if (!gtk_tree_selection_count_selected_rows (selection))
2068 {
2069 return;
2070 }
2071
2072 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL, NULL);
2073
2074 data.index = 1;
2075 remote_browser.fs_ops->readdir (&data.iter, remote_browser.dir,
2076 remote_browser.data);
2077 gtk_tree_selection_selected_foreach (selection, elektroid_add_upload_task,
2078 &data);
2079 free_item_iterator (&data.iter);
2080
2081 gtk_widget_set_sensitive (rx_sysex_button, FALSE);
2082 gtk_widget_set_sensitive (tx_sysex_button, FALSE);
2083 gtk_widget_set_sensitive (os_upgrade_button, FALSE);
2084
2085 if (!queued)
2086 {
2087 elektroid_run_next_task (NULL);
2088 }
2089 }
2090
2091 static gpointer
2092 elektroid_download_task (gpointer userdata)
2093 {
2094 gint res;
2095 GByteArray *array;
2096
2097 array = g_byte_array_new ();
2098
2099 debug_print (1, "Remote path: %s\n", transfer.src);
2100 debug_print (1, "Local path: %s\n", transfer.dst);
2101
2102 res =
2103 transfer.fs_ops->download (transfer.src, array,
2104 &transfer.control, remote_browser.data);
2105 g_idle_add (elektroid_check_connector_bg, NULL);
2106
2107 g_mutex_lock (&transfer.control.mutex);
2108 if (res && transfer.control.active)
2109 {
2110 error_print ("Error while downloading\n");
2111 transfer.status = COMPLETED_ERROR;
2112 }
2113 else
2114 {
2115 if (transfer.control.active)
2116 {
2117 debug_print (1, "Writing %d bytes to file %s (filesystem %s)...\n",
2118 array->len, transfer.dst,
2119 elektroid_get_fs_name (transfer.fs_ops->fs));
2120
2121 res =
2122 transfer.fs_ops->save (transfer.dst, array, &transfer.control);
2123 if (!res)
2124 {
2125 transfer.status = COMPLETED_OK;
2126 }
2127 }
2128 else
2129 {
2130 transfer.status = CANCELED;
2131 }
2132
2133 g_byte_array_free (array, TRUE);
2134 g_free (transfer.control.data);
2135 transfer.control.data = NULL;
2136 }
2137 g_mutex_unlock (&transfer.control.mutex);
2138
2139 g_idle_add (elektroid_complete_running_task, NULL);
2140 g_idle_add (elektroid_run_next_task, NULL);
2141
2142 return NULL;
2143 }
2144
2145 static void
2146 elektroid_add_download_task_path (const gchar * rel_path,
2147 const gchar * src_dir,
2148 const gchar * dst_dir,
2149 struct item_iterator *remote_dir_iter)
2150 {
2151 struct item_iterator iter, iter_copy;
2152 gchar *path, *id, *download_path, *dst_abs_dirc, *dst_abs_dir;
21502153 gchar *src_abs_path = chain_path (src_dir, rel_path);
21512154 gchar *dst_abs_path = chain_path (dst_dir, rel_path);
2152 DIR *dir = opendir (src_abs_path);
2153
2154 if (!dir)
2155 {
2156 dst_abs_dir = dirname (dst_abs_path);
2157 elektroid_add_task (UPLOAD, src_abs_path, dst_abs_dir);
2155
2156 if (remote_browser.
2157 fs_ops->readdir (&iter, src_abs_path, remote_browser.data))
2158 {
2159 dst_abs_dirc = strdup (dst_abs_path);
2160 dst_abs_dir = dirname (dst_abs_dirc);
2161 download_path =
2162 connector_get_download_path (&connector, remote_dir_iter,
2163 remote_browser.fs_ops, dst_abs_dir,
2164 src_abs_path);
2165 elektroid_add_task (DOWNLOAD, src_abs_path, download_path,
2166 remote_browser.fs_ops->fs);
2167 g_free (dst_abs_dirc);
2168 g_free (download_path);
21582169 goto cleanup_not_dir;
21592170 }
21602171
2161 if (elektroid_remote_mkdir (dst_abs_path))
2162 {
2163 error_print ("Error while creating remote %s dir\n", dst_abs_path);
2172 if (local_browser.fs_ops->mkdir (dst_abs_path, NULL))
2173 {
2174 error_print ("Error while creating local %s dir\n", dst_abs_path);
21642175 goto cleanup;
21652176 }
21662177
2167 if (!strchr (rel_path, '/'))
2168 {
2169 remote_browser.load_dir (NULL);
2170 }
2171
2172 while ((dirent = readdir (dir)) != NULL)
2173 {
2174 if (dirent->d_name[0] == '.')
2175 {
2176 continue;
2177 }
2178
2179 if (dirent->d_type == DT_DIR
2180 || (dirent->d_type == DT_REG
2181 && elektroid_valid_file (dirent->d_name)))
2182 {
2183 if (dirent->d_type == DT_DIR)
2184 {
2185 path = chain_path (rel_path, dirent->d_name);
2186 elektroid_add_upload_task_path (path, src_dir, dst_dir);
2187 free (path);
2188 }
2189 else
2190 {
2191 path = chain_path (src_abs_path, dirent->d_name);
2192 elektroid_add_task (UPLOAD, path, dst_abs_path);
2193 free (path);
2194 }
2195 }
2196 }
2178 copy_item_iterator (&iter_copy, &iter, TRUE);
2179 while (!next_item_iterator (&iter))
2180 {
2181 id = remote_browser.fs_ops->getid (&iter.item);
2182 path = chain_path (rel_path, id);
2183 elektroid_add_download_task_path (path, src_dir, dst_dir, &iter_copy);
2184 g_free (path);
2185 g_free (id);
2186 }
2187 free_item_iterator (&iter_copy);
21972188
21982189 cleanup:
2199 closedir (dir);
2190 free_item_iterator (&iter);
22002191 cleanup_not_dir:
22012192 free (dst_abs_path);
22022193 free (src_abs_path);
22032194 }
22042195
22052196 static void
2206 elektroid_add_upload_task (GtkTreeModel * model,
2207 GtkTreePath * path,
2208 GtkTreeIter * iter, gpointer userdata)
2209 {
2210 gchar *name;
2211
2212 browser_get_item_info (model, iter, NULL, &name, NULL);
2213 elektroid_add_upload_task_path (name, local_browser.dir,
2214 remote_browser.dir);
2215 g_free (name);
2216 }
2217
2218 static void
2219 elektroid_add_upload_tasks (GtkWidget * object, gpointer data)
2220 {
2221 gboolean queued;
2222 GtkTreeIter iter;
2223 GtkTreeSelection *selection =
2224 gtk_tree_view_get_selection (GTK_TREE_VIEW (local_browser.view));
2225
2226 if (!gtk_tree_selection_count_selected_rows (selection))
2227 {
2228 return;
2229 }
2230
2231 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL);
2232
2233 gtk_tree_selection_selected_foreach (selection,
2234 elektroid_add_upload_task, NULL);
2235
2236 gtk_widget_set_sensitive (rx_sysex_button, FALSE);
2237 gtk_widget_set_sensitive (tx_sysex_button, FALSE);
2238 gtk_widget_set_sensitive (os_upgrade_button, FALSE);
2239
2240 if (!queued)
2241 {
2242 elektroid_run_next_task (NULL);
2243 }
2244 }
2245
2246 static gpointer
2247 elektroid_download_task (gpointer data)
2248 {
2249 GArray *sample;
2250 size_t frames;
2251 gchar *dst_path;
2252 gchar *basec;
2253 gchar *bname;
2254 gchar *new_filename;
2255
2256 debug_print (1, "Remote path: %s\n", sample_transfer.src);
2257
2258 basec = strdup (sample_transfer.src);
2259 bname = basename (basec);
2260 new_filename = malloc (PATH_MAX);
2261 snprintf (new_filename, PATH_MAX, "%s.wav", bname);
2262 free (basec);
2263 dst_path = chain_path (sample_transfer.dst, new_filename);
2264 free (new_filename);
2265
2266 debug_print (1, "Local path: %s\n", dst_path);
2267
2268 sample =
2269 connector_download (&connector, sample_transfer.src,
2270 &sample_transfer.transfer, elektroid_update_progress);
2271 g_idle_add (elektroid_check_connector_bg, NULL);
2272
2273 if (sample == NULL && sample_transfer.transfer.active)
2274 {
2275 error_print ("Error while downloading\n");
2276 sample_transfer.status = COMPLETED_ERROR;
2277 }
2278 else
2279 {
2280 g_mutex_lock (&sample_transfer.transfer.mutex);
2281 if (sample_transfer.transfer.active)
2282 {
2283 elektroid_local_mkdir (sample_transfer.dst);
2284 debug_print (1, "Writing to file %s...\n", dst_path);
2285 frames = sample_save (sample, dst_path);
2286 debug_print (1, "%zu frames written\n", frames);
2287 free (dst_path);
2288 sample_transfer.status = COMPLETED_OK;
2289 }
2290 else
2291 {
2292 sample_transfer.status = CANCELED;
2293 }
2294 g_mutex_unlock (&sample_transfer.transfer.mutex);
2295 }
2296
2297 if (sample)
2298 {
2299 g_array_free (sample, TRUE);
2300 if (strcmp (sample_transfer.dst, local_browser.dir) == 0)
2301 {
2302 g_idle_add (local_browser.load_dir, NULL);
2303 }
2304 }
2305
2306 g_idle_add (elektroid_complete_running_task, NULL);
2307 g_idle_add (elektroid_run_next_task, NULL);
2308
2309 return NULL;
2310 }
2311
2312 static void
2313 elektroid_add_download_task_path (gchar * rel_path, gchar * src_dir,
2314 gchar * dst_dir)
2315 {
2316 gchar *path;
2317 gchar *dst_abs_dir;
2318 struct connector_dir_iterator *d_iter;
2319 gchar *src_abs_path = chain_path (src_dir, rel_path);
2320 gchar *dst_abs_path = chain_path (dst_dir, rel_path);
2321
2322 d_iter = connector_read_dir (&connector, src_abs_path);
2323 elektroid_check_connector ();
2324 if (!d_iter)
2325 {
2326 dst_abs_dir = dirname (dst_abs_path);
2327 elektroid_add_task (DOWNLOAD, src_abs_path, dst_abs_dir);
2328 goto cleanup_not_dir;
2329 }
2330
2331 if (elektroid_local_mkdir (dst_abs_path))
2332 {
2333 error_print ("Error while creating local %s dir\n", dst_abs_path);
2334 goto cleanup;
2335 }
2336
2337 if (!strchr (rel_path, '/'))
2338 {
2339 local_browser.load_dir (NULL);
2340 }
2341
2342 while (!connector_get_next_dentry (d_iter))
2343 {
2344 if (d_iter->type == ELEKTROID_DIR)
2345 {
2346 path = chain_path (rel_path, d_iter->dentry);
2347 elektroid_add_download_task_path (path, src_dir, dst_dir);
2348 free (path);
2349 }
2350 else
2351 {
2352 path = chain_path (src_abs_path, d_iter->dentry);
2353 elektroid_add_task (DOWNLOAD, path, dst_abs_path);
2354 free (path);
2355 }
2356 }
2357
2358 cleanup:
2359 connector_free_dir_iterator (d_iter);
2360 cleanup_not_dir:
2361 free (dst_abs_path);
2362 free (src_abs_path);
2363 }
2364
2365 static void
23662197 elektroid_add_download_task (GtkTreeModel * model,
23672198 GtkTreePath * path,
23682199 GtkTreeIter * iter, gpointer data)
23692200 {
2370 gchar *name;
2371
2372 browser_get_item_info (model, iter, NULL, &name, NULL);
2373 elektroid_add_download_task_path (name, remote_browser.dir,
2374 local_browser.dir);
2375 g_free (name);
2201 struct item *item = browser_get_item (model, iter);
2202 char *id = remote_browser.fs_ops->getid (item);
2203
2204 elektroid_add_download_task_path (id, remote_browser.dir,
2205 local_browser.dir, data);
2206 g_free (id);
2207 browser_free_item (item);
23762208 }
23772209
23782210 static void
23802212 {
23812213 gboolean queued;
23822214 GtkTreeIter iter;
2215 struct item_iterator item_iterator;
23832216 GtkTreeSelection *selection =
23842217 gtk_tree_view_get_selection (GTK_TREE_VIEW (remote_browser.view));
23852218
23882221 return;
23892222 }
23902223
2391 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL);
2392
2393 gtk_tree_selection_selected_foreach (selection,
2394 elektroid_add_download_task, NULL);
2224 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL, NULL);
2225
2226 remote_browser.fs_ops->readdir (&item_iterator, remote_browser.dir,
2227 remote_browser.data);
2228 gtk_tree_selection_selected_foreach (selection, elektroid_add_download_task,
2229 &item_iterator);
2230 free_item_iterator (&item_iterator);
23952231
23962232 gtk_widget_set_sensitive (rx_sysex_button, FALSE);
23972233 gtk_widget_set_sensitive (tx_sysex_button, FALSE);
24512287 else if (event->keyval == GDK_KEY_F2)
24522288 {
24532289 count = browser_get_selected_items_count (browser);
2454 if (count == 1)
2290 if (count == 1 && browser->fs_ops->rename)
24552291 {
24562292 elektroid_rename_item (NULL, browser);
24572293 }
24592295 }
24602296 else if (event->keyval == GDK_KEY_Delete)
24612297 {
2462 count = browser_get_selected_items_count (browser);
2463 if (count)
2298 if (browser_get_selected_items_count (browser) > 0
2299 && browser->fs_ops->delete)
24642300 {
24652301 elektroid_delete_files (NULL, browser);
24662302 }
24682304 }
24692305 else if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_r)
24702306 {
2471 browser->load_dir (NULL);
2307 browser_load_dir (browser);
24722308 return TRUE;
24732309 }
24742310 else if (event->state & GDK_CONTROL_MASK
24992335 {
25002336 if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_Left)
25012337 {
2502 elektroid_add_download_tasks (NULL, NULL);
2338 if (remote_browser.fs_ops->download)
2339 {
2340 struct connector *connector = remote_browser.data;
2341 connector_enable_dir_cache (connector);
2342 elektroid_add_download_tasks (NULL, NULL);
2343 connector_disable_dir_cache (connector);
2344 }
25032345 return TRUE;
25042346 }
25052347 else
25192361 {
25202362 if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_Right)
25212363 {
2522 elektroid_add_upload_tasks (NULL, NULL);
2364 if (remote_browser.fs_ops->upload)
2365 {
2366 elektroid_add_upload_tasks (NULL, NULL);
2367 }
25232368 return TRUE;
25242369 }
25252370 else
25292374 }
25302375
25312376 return FALSE;
2377 }
2378
2379 static void
2380 elektroid_set_fs (GtkWidget * object, gpointer data)
2381 {
2382 GtkTreeIter iter;
2383 GtkTreeSortable *sortable;
2384 GValue fsv = G_VALUE_INIT;
2385 enum connector_fs fs;
2386
2387 if (gtk_combo_box_get_active_iter (fs_combo, &iter) == TRUE)
2388 {
2389 gtk_tree_model_get_value (GTK_TREE_MODEL (fs_list_store),
2390 &iter, FS_LIST_STORE_ID_FIELD, &fsv);
2391 fs = g_value_get_uint (&fsv);
2392
2393 remote_browser.fs_ops = connector_get_fs_operations (fs);
2394 remote_browser.file_icon = elektroid_get_inventory_icon_for_fs (fs);
2395 strcpy (remote_browser.dir, "/");
2396 browser_load_dir (&remote_browser);
2397
2398 local_browser.file_icon = remote_browser.file_icon;
2399 elektroid_set_file_extensions_for_fs (&local_browser.extensions, fs);
2400 browser_load_dir (&local_browser);
2401
2402 gtk_widget_set_sensitive (remote_browser.up_button,
2403 remote_browser.fs_ops->readdir != NULL);
2404 gtk_widget_set_visible (remote_browser.add_dir_button,
2405 remote_browser.fs_ops->mkdir != NULL);
2406 gtk_widget_set_sensitive (remote_browser.refresh_button,
2407 remote_browser.fs_ops->readdir != NULL);
2408
2409 gtk_widget_set_visible (remote_rename_menuitem,
2410 remote_browser.fs_ops->rename != NULL);
2411 gtk_widget_set_visible (remote_delete_menuitem,
2412 remote_browser.fs_ops->delete != NULL);
2413 gtk_widget_set_visible (local_audio_box, fs == FS_SAMPLES);
2414 gtk_tree_view_column_set_visible (remote_tree_view_index_column,
2415 fs == FS_DATA_PRJ
2416 || fs == FS_DATA_SND);
2417
2418 if (fs != FS_SAMPLES)
2419 {
2420 audio_stop (&audio, TRUE);
2421 }
2422
2423 sortable =
2424 GTK_TREE_SORTABLE (gtk_tree_view_get_model (remote_browser.view));
2425
2426 if (fs == FS_SAMPLES || fs == FS_RAW_PRESETS)
2427 {
2428 gtk_tree_sortable_set_sort_func (sortable,
2429 BROWSER_LIST_STORE_NAME_FIELD,
2430 browser_sort_samples, NULL, NULL);
2431 gtk_tree_sortable_set_sort_column_id (sortable,
2432 BROWSER_LIST_STORE_NAME_FIELD,
2433 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
2434 }
2435 else if (fs == FS_DATA_PRJ || fs == FS_DATA_SND)
2436 {
2437 gtk_tree_sortable_set_sort_func (sortable,
2438 BROWSER_LIST_STORE_INDEX_FIELD,
2439 browser_sort_data, NULL, NULL);
2440 gtk_tree_sortable_set_sort_column_id (sortable,
2441 BROWSER_LIST_STORE_INDEX_FIELD,
2442 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
2443 }
2444 }
2445 }
2446
2447 static void
2448 elektroid_fill_fs_combo ()
2449 {
2450 gtk_list_store_clear (fs_list_store);
2451
2452 for (int fs = FS_SAMPLES, i = 0; fs <= FS_DATA_SND; fs = fs << 1, i++)
2453 {
2454 if (GUI_FSS & fs && connector.device_desc->fss & fs)
2455 {
2456 gtk_list_store_insert_with_values (fs_list_store, NULL, -1,
2457 FS_LIST_STORE_ID_FIELD,
2458 fs,
2459 FS_LIST_STORE_ICON_FIELD,
2460 ELEKTROID_FS_ICONS[i],
2461 FS_LIST_STORE_NAME_FIELD,
2462 elektroid_get_fs_name (fs), -1);
2463 }
2464 }
2465
2466 debug_print (1, "Selecting first filesystem...\n");
2467 gtk_combo_box_set_active (fs_combo, 0);
25322468 }
25332469
25342470 static void
25462482 }
25472483
25482484 gtk_tree_model_get_value (GTK_TREE_MODEL (devices_list_store),
2549 &iter, 0, &cardv);
2485 &iter, DEVICES_LIST_STORE_CARD_FIELD, &cardv);
25502486
25512487 card = g_value_get_uint (&cardv);
25522488
25572493
25582494 if (elektroid_check_connector ())
25592495 {
2560 strcpy (remote_browser.dir, "/");
2561 remote_browser.load_dir (NULL);
2562 }
2496 elektroid_fill_fs_combo ();
2497 }
2498 }
2499 }
2500
2501 static void
2502 elektroid_dnd_received_local (const gchar * type_name, const gchar * dir,
2503 const gchar * name, const gchar * filename,
2504 struct item_iterator *remote_item_iterator)
2505 {
2506 gchar *dst_path;
2507 gint res;
2508
2509 if (strcmp (type_name, TEXT_URI_LIST_STD) == 0)
2510 {
2511 if (strcmp (dir, local_browser.dir))
2512 {
2513 dst_path = chain_path (local_browser.dir, name);
2514 res = local_browser.fs_ops->move (filename, dst_path, NULL);
2515 if (res)
2516 {
2517 show_error_msg (_
2518 ("Error while moving from “%s” to “%s”: %s."),
2519 filename, dst_path, g_strerror (res));
2520 }
2521 g_free (dst_path);
2522 }
2523 else
2524 {
2525 debug_print (1, MSG_WARN_SAME_SRC_DST);
2526 }
2527 }
2528 else if (strcmp (type_name, TEXT_URI_LIST_ELEKTROID) == 0)
2529 {
2530 elektroid_add_download_task_path (name, dir, local_browser.dir,
2531 remote_item_iterator);
2532 }
2533 }
2534
2535 static void
2536 elektroid_dnd_received_remote (const gchar * type_name, const gchar * dir,
2537 const gchar * name, const gchar * filename,
2538 struct item_iterator *remote_item_iterator,
2539 gint32 * next_idx)
2540 {
2541 gchar *dst_path;
2542 gint res;
2543
2544 if (strcmp (type_name, TEXT_URI_LIST_ELEKTROID) == 0)
2545 {
2546 if (strcmp (dir, remote_browser.dir))
2547 {
2548 dst_path =
2549 connector_get_upload_path (&connector,
2550 remote_item_iterator,
2551 remote_browser.fs_ops,
2552 remote_browser.dir, name, next_idx);
2553 res =
2554 remote_browser.fs_ops->move (filename, dst_path,
2555 remote_browser.data);
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 browser_load_dir (&remote_browser);
2564 }
2565 else
2566 {
2567 debug_print (1, MSG_WARN_SAME_SRC_DST);
2568 }
2569 }
2570 else if (strcmp (type_name, TEXT_URI_LIST_STD) == 0)
2571 {
2572 elektroid_add_upload_task_path (name, dir, remote_browser.dir,
2573 remote_item_iterator, next_idx);
25632574 }
25642575 }
25652576
25762587 gchar *path_dirname;
25772588 gchar *name;
25782589 gchar *dir;
2579 gchar *dest_path;
25802590 GtkTreeIter iter;
25812591 gboolean queued;
25822592 GdkAtom type;
25832593 gchar *type_name;
2584 gint res;
2585
2586 if (selection_data != NULL && gtk_selection_data_get_length (selection_data)
2587 && info == TARGET_STRING)
2588 {
2589 type = gtk_selection_data_get_data_type (selection_data);
2590 type_name = gdk_atom_name (type);
2591
2592 data = (gchar *) gtk_selection_data_get_data (selection_data);
2593 debug_print (1, "DND received data (%s):\n%s\n", type_name, data);
2594
2595 uris = g_uri_list_extract_uris (data);
2596 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL);
2597
2598 for (int i = 0; uris[i] != NULL; i++)
2599 {
2600 filename = g_filename_from_uri (uris[i], NULL, NULL);
2601 path_basename = strdup (filename);
2602 path_dirname = strdup (filename);
2603 name = basename (path_basename);
2604 dir = dirname (path_dirname);
2605
2606 if (widget == GTK_WIDGET (local_browser.view))
2607 {
2608 if (strcmp (type_name, TEXT_URI_LIST_STD) == 0)
2609 {
2610 if (strcmp (dir, local_browser.dir))
2611 {
2612 dest_path = chain_path (local_browser.dir, name);
2613 res = elektroid_local_rename (filename, dest_path);
2614 if (res)
2615 {
2616 show_error_msg
2617 (_
2618 ("Error while moving from “%s” to “%s”: %s."),
2619 filename, dest_path, g_strerror (errno));
2620 }
2621 g_free (dest_path);
2622 elektroid_load_local_dir (NULL);
2623 }
2624 else
2625 {
2626 debug_print (1,
2627 "Same source and destination path. Skipping...\n");
2628 }
2629 }
2630 else if (strcmp (type_name, TEXT_URI_LIST_ELEKTROID) == 0)
2631 {
2632 elektroid_add_download_task_path (name, dir,
2633 local_browser.dir);
2634 }
2635 }
2636 else if (widget == GTK_WIDGET (remote_browser.view))
2637 {
2638 if (strcmp (type_name, TEXT_URI_LIST_ELEKTROID) == 0)
2639 {
2640 if (strcmp (dir, remote_browser.dir))
2641 {
2642 dest_path = chain_path (remote_browser.dir, name);
2643 res = elektroid_remote_rename (filename, dest_path);
2644 if (res)
2645 {
2646 show_error_msg
2647 (_
2648 ("Error while moving from “%s” to “%s”: %s."),
2649 filename, dest_path, g_strerror (errno));
2650 }
2651 g_free (dest_path);
2652 elektroid_load_remote_dir (NULL);
2653 }
2654 else
2655 {
2656 debug_print (1,
2657 "Same source and destination path. Skipping...\n");
2658 }
2659 }
2660 else if (strcmp (type_name, TEXT_URI_LIST_STD) == 0)
2661 {
2662 elektroid_add_upload_task_path (name, dir,
2663 remote_browser.dir);
2664 }
2665 }
2666
2667 g_free (path_basename);
2668 g_free (path_dirname);
2669 g_free (filename);
2670 }
2671
2672 if (!queued)
2673 {
2674 elektroid_run_next_task (NULL);
2675 }
2676
2677 g_strfreev (uris);
2678 }
2679
2594 gint32 next_idx = 1;
2595 struct item_iterator remote_item_iterator;
2596 struct connector *connector = remote_browser.data;
2597
2598 if (selection_data == NULL
2599 || !gtk_selection_data_get_length (selection_data)
2600 || info != TARGET_STRING)
2601 {
2602 goto end;
2603 }
2604
2605 type = gtk_selection_data_get_data_type (selection_data);
2606 type_name = gdk_atom_name (type);
2607
2608 data = (gchar *) gtk_selection_data_get_data (selection_data);
2609 debug_print (1, "DND received data (%s):\n%s\n", type_name, data);
2610
2611 uris = g_uri_list_extract_uris (data);
2612 queued = elektroid_get_next_queued_task (&iter, NULL, NULL, NULL, NULL);
2613
2614 if (widget == GTK_WIDGET (local_browser.view))
2615 {
2616 connector_enable_dir_cache (connector);
2617 }
2618
2619 remote_browser.fs_ops->readdir (&remote_item_iterator, remote_browser.dir,
2620 connector);
2621
2622 for (int i = 0; uris[i] != NULL; i++)
2623 {
2624 filename = g_filename_from_uri (uris[i], NULL, NULL);
2625 path_basename = strdup (filename);
2626 path_dirname = strdup (filename);
2627 name = basename (path_basename);
2628 dir = dirname (path_dirname);
2629
2630 if (widget == GTK_WIDGET (local_browser.view))
2631 {
2632 elektroid_dnd_received_local (type_name, dir, name, filename,
2633 &remote_item_iterator);
2634 }
2635 else if (widget == GTK_WIDGET (remote_browser.view))
2636 {
2637 elektroid_dnd_received_remote (type_name, dir, name, filename,
2638 &remote_item_iterator, &next_idx);
2639 }
2640
2641 g_free (path_basename);
2642 g_free (path_dirname);
2643 g_free (filename);
2644 }
2645
2646 free_item_iterator (&remote_item_iterator);
2647
2648 if (widget == GTK_WIDGET (local_browser.view))
2649 {
2650 connector_disable_dir_cache (connector);
2651 }
2652
2653 if (!queued)
2654 {
2655 elektroid_run_next_task (NULL);
2656 }
2657
2658 g_strfreev (uris);
2659
2660 end:
26802661 gtk_drag_finish (context, TRUE, TRUE, time);
26812662 }
26822663
26862667 GtkSelectionData * selection_data,
26872668 guint info, guint time, gpointer user_data)
26882669 {
2670 GdkAtom type;
2671 gchar *type_name;
26892672 struct browser *browser = user_data;
26902673
26912674 switch (info)
26992682 (guchar *) browser->dnd_data->str,
27002683 browser->dnd_data->len);
27012684
2702 debug_print (1, "DND sent data:\n%s\n", browser->dnd_data->str);
2685 type = gtk_selection_data_get_data_type (selection_data);
2686 type_name = gdk_atom_name (type);
2687 debug_print (1, "DND sent data (%s):\n%s\n", type_name,
2688 browser->dnd_data->str);
2689
27032690 break;
27042691 default:
27052692 error_print ("DND type not supported\n");
27332720 GtkTreePath *path;
27342721 GtkTreeModel *model;
27352722 GtkTreeIter iter;
2736 gchar type;
2737 gchar *icon;
27382723 gchar *spath;
27392724 gint tx;
27402725 gint ty;
27412726 GtkTreeSelection *selection;
2727 struct item *item;
27422728 struct browser *browser = user_data;
27432729
27442730 gtk_tree_view_convert_widget_to_bin_window_coords
27652751 model =
27662752 GTK_TREE_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
27672753 gtk_tree_model_get_iter (model, &iter, path);
2768 browser_get_item_info (model, &iter, &icon, NULL, NULL);
2769 type = get_type_from_inventory_icon (icon);
2770
2771 if (type == ELEKTROID_DIR && (!browser->dnd_motion_path
2772 || (browser->dnd_motion_path
2773 &&
2774 gtk_tree_path_compare
2775 (browser->dnd_motion_path, path))))
2754 item = browser_get_item (model, &iter);
2755
2756 if (item->type == ELEKTROID_DIR && (!browser->dnd_motion_path
2757 || (browser->dnd_motion_path
2758 &&
2759 gtk_tree_path_compare
2760 (browser->dnd_motion_path,
2761 path))))
27762762 {
27772763 if (browser->dnd_timeout_function_id)
27782764 {
27802766 browser->dnd_timeout_function_id = 0;
27812767 }
27822768 browser->dnd_timeout_function_id =
2783 g_timeout_add (UP_BUTTON_DND_TIMEOUT, elektroid_drag_list_timeout,
2784 browser);
2785 }
2769 g_timeout_add (DND_TIMEOUT, elektroid_drag_list_timeout, browser);
2770 }
2771
2772 browser_free_item (item);
27862773 }
27872774 else
27882775 {
28412828 browser->dnd_timeout_function_id = 0;
28422829 }
28432830 browser->dnd_timeout_function_id =
2844 g_timeout_add (UP_BUTTON_DND_TIMEOUT, elektroid_drag_up_timeout, browser);
2831 g_timeout_add (DND_TIMEOUT, elektroid_drag_up_timeout, browser);
28452832
28462833 return TRUE;
28472834 }
28572844 g_source_remove (browser->dnd_timeout_function_id);
28582845 browser->dnd_timeout_function_id = 0;
28592846 }
2847 }
2848
2849 static void
2850 elektroid_notify_local_dir_change (struct browser *browser)
2851 {
2852 notifier_set_dir (&notifier, browser->dir);
28602853 }
28612854
28622855 static void
28832876 }
28842877
28852878 static int
2886 elektroid_run (int argc, char *argv[], gchar * local_dir)
2879 elektroid_run (int argc, char *argv[])
28872880 {
28882881 GtkBuilder *builder;
28892882 GtkCssProvider *css_provider;
29652958 GTK_WIDGET (gtk_builder_get_object (builder, "hostname_label"));
29662959
29672960 remote_box = GTK_WIDGET (gtk_builder_get_object (builder, "remote_box"));
2961 local_audio_box =
2962 GTK_WIDGET (gtk_builder_get_object (builder, "local_audio_box"));
29682963 waveform_draw_area =
29692964 GTK_WIDGET (gtk_builder_get_object (builder, "waveform_draw_area"));
29702965 play_button = GTK_WIDGET (gtk_builder_get_object (builder, "play_button"));
30663061 GTK_ENTRY (gtk_builder_get_object (builder, "remote_dir_entry")),
30673062 .menu = GTK_MENU (gtk_builder_get_object (builder, "remote_menu")),
30683063 .dir = malloc (PATH_MAX),
3069 .load_dir = elektroid_load_remote_dir,
30703064 .check_selection = elektroid_remote_check_selection,
3071 .rename = elektroid_remote_rename,
3072 .delete = elektroid_remote_delete,
3073 .mkdir = elektroid_remote_mkdir
3065 .file_icon = NULL,
3066 .fs_ops = connector_get_fs_operations (-1),
3067 .data = &connector,
3068 .notify_dir_change = NULL,
3069 .check_callback = elektroid_check_connector
30743070 };
3071 remote_tree_view_index_column =
3072 GTK_TREE_VIEW_COLUMN (gtk_builder_get_object
3073 (builder, "remote_tree_view_index_column"));
30753074
30763075 g_signal_connect (gtk_tree_view_get_selection (remote_browser.view),
30773076 "changed", G_CALLBACK (browser_selection_changed),
30973096 g_signal_connect (remote_browser.view, "drag-data-get",
30983097 G_CALLBACK (elektroid_dnd_get), &remote_browser);
30993098 g_signal_connect (remote_browser.view, "drag-data-received",
3100 G_CALLBACK (elektroid_dnd_received), NULL);
3099 G_CALLBACK (elektroid_dnd_received), &remote_browser);
31013100 g_signal_connect (remote_browser.view, "drag-motion",
31023101 G_CALLBACK (elektroid_drag_motion_list), &remote_browser);
31033102 g_signal_connect (remote_browser.view, "drag-leave",
31063105 G_CALLBACK (elektroid_drag_motion_up), &remote_browser);
31073106 g_signal_connect (remote_browser.up_button, "drag-leave",
31083107 G_CALLBACK (elektroid_drag_leave_up), &remote_browser);
3109
3110 sortable =
3111 GTK_TREE_SORTABLE (gtk_tree_view_get_model (remote_browser.view));
3112 gtk_tree_sortable_set_sort_func (sortable, BROWSER_LIST_STORE_NAME_FIELD,
3113 browser_sort, NULL, NULL);
3114 gtk_tree_sortable_set_sort_column_id (sortable,
3115 BROWSER_LIST_STORE_NAME_FIELD,
3116 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
31173108
31183109 gtk_drag_source_set ((GtkWidget *) remote_browser.view, GDK_BUTTON1_MASK,
31193110 TARGET_ENTRIES_REMOTE_SRC, TARGET_ENTRIES_REMOTE_SRC_N,
31403131 GTK_ENTRY (gtk_builder_get_object (builder, "local_dir_entry")),
31413132 .menu = GTK_MENU (gtk_builder_get_object (builder, "local_menu")),
31423133 .dir = malloc (PATH_MAX),
3143 .load_dir = elektroid_load_local_dir,
31443134 .check_selection = elektroid_local_check_selection,
3145 .rename = elektroid_local_rename,
3146 .delete = elektroid_local_delete,
3147 .mkdir = elektroid_local_mkdir
3135 .file_icon = elektroid_get_inventory_icon_for_fs (FS_SAMPLES),
3136 .extensions = NULL,
3137 .fs_ops = &FS_LOCAL_OPERATIONS,
3138 .data = NULL,
3139 .notify_dir_change = elektroid_notify_local_dir_change,
3140 .check_callback = NULL
31483141 };
31493142
31503143 g_signal_connect (gtk_tree_view_get_selection (local_browser.view),
31713164 g_signal_connect (local_browser.view, "drag-data-get",
31723165 G_CALLBACK (elektroid_dnd_get), &local_browser);
31733166 g_signal_connect (local_browser.view, "drag-data-received",
3174 G_CALLBACK (elektroid_dnd_received), NULL);
3167 G_CALLBACK (elektroid_dnd_received), &local_browser);
31753168 g_signal_connect (local_browser.view, "drag-motion",
31763169 G_CALLBACK (elektroid_drag_motion_list), &local_browser);
31773170 g_signal_connect (local_browser.view, "drag-leave",
31833176
31843177 sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (local_browser.view));
31853178 gtk_tree_sortable_set_sort_func (sortable, BROWSER_LIST_STORE_NAME_FIELD,
3186 browser_sort, NULL, NULL);
3179 browser_sort_samples, NULL, NULL);
31873180 gtk_tree_sortable_set_sort_column_id (sortable,
31883181 BROWSER_LIST_STORE_NAME_FIELD,
31893182 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
31993192 TARGET_ENTRIES_UP_BUTTON_DST,
32003193 TARGET_ENTRIES_UP_BUTTON_DST_N, GDK_ACTION_COPY);
32013194
3202 audio_init (&audio, elektroid_set_volume_callback);
3195 audio_init (&audio, elektroid_set_volume_callback, elektroid_redraw_sample);
32033196
32043197 devices_list_store =
32053198 GTK_LIST_STORE (gtk_builder_get_object (builder, "devices_list_store"));
32323225
32333226 gtk_statusbar_push (status_bar, 0, _("Not connected"));
32343227 elektroid_loop_clicked (loop_button, NULL);
3235 autoplay = gtk_switch_get_active (GTK_SWITCH (autoplay_switch));
3228 gtk_switch_set_active (GTK_SWITCH (autoplay_switch), preferences.autoplay);
3229
3230 fs_list_store =
3231 GTK_LIST_STORE (gtk_builder_get_object (builder, "fs_list_store"));
3232 fs_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "fs_combo"));
3233 g_signal_connect (fs_combo, "changed", G_CALLBACK (elektroid_set_fs), NULL);
32363234
32373235 gtk_widget_set_sensitive (remote_box, FALSE);
32383236 gtk_widget_set_sensitive (rx_sysex_button, FALSE);
32393237 gtk_widget_set_sensitive (tx_sysex_button, FALSE);
32403238 gtk_widget_set_sensitive (os_upgrade_button, FALSE);
32413239
3242 elektroid_load_devices (TRUE);
3240 local_browser.dir = preferences.local_dir;
3241 elektroid_load_devices (TRUE); //This triggers a local browser reload due to the extensions and icons selected for the fs
32433242
32443243 gethostname (hostname, LABEL_MAX);
32453244 gtk_label_set_text (GTK_LABEL (hostname_label), hostname);
32463245
3247 strcpy (local_browser.dir, local_dir);
3248 local_browser.load_dir (NULL);
32493246 debug_print (1, "Creating notifier thread...\n");
3250 notifier_init (&notifier, elektroid_load_local_dir,
3251 elektroid_go_up_local_dir);
3252 notifier_set_dir (&notifier, local_dir);
3247 notifier_init (&notifier, &local_browser);
3248 notifier_set_dir (&notifier, preferences.local_dir);
32533249 notifier_thread = g_thread_new ("notifier_thread", notifier_run, &notifier);
3254 free (local_dir);
32553250
32563251 gtk_widget_show (main_window);
32573252 gtk_main ();
32583253
32593254 free (remote_browser.dir);
3260 free (local_browser.dir);
32613255
32623256 if (connector_check (&connector))
32633257 {
32653259 }
32663260
32673261 audio_destroy (&audio);
3268 return 0;
3262 return EXIT_SUCCESS;
32693263 }
32703264
32713265 static gboolean
32793273 elektroid_print_help (gchar * executable_path)
32803274 {
32813275 gchar *exec_name;
3282 struct option *option;
3276 const struct option *option;
32833277
32843278 fprintf (stderr, "%s\n", PACKAGE_STRING);
32853279 exec_name = basename (executable_path);
32863280 fprintf (stderr, "Usage: %s [options]\n", exec_name);
32873281 fprintf (stderr, "Options:\n");
3288 option = options;
3282 option = ELEKTROID_OPTIONS;
32893283 while (option->name)
32903284 {
32913285 fprintf (stderr, " --%s, -%c", option->name, option->val);
33013295 int
33023296 main (int argc, char *argv[])
33033297 {
3304 gint opt;
3298 gint opt, ret;
33053299 gchar *local_dir = NULL;
33063300 gint vflg = 0, dflg = 0, errflg = 0;
33073301 int long_index = 0;
33143308 bindtextdomain (PACKAGE, LOCALEDIR);
33153309 textdomain (PACKAGE);
33163310
3317 while ((opt = getopt_long (argc, argv, "l:vh", options, &long_index)) != -1)
3311 while ((opt =
3312 getopt_long (argc, argv, "l:vh", ELEKTROID_OPTIONS,
3313 &long_index)) != -1)
33183314 {
33193315 switch (opt)
33203316 {
33493345 exit (EXIT_FAILURE);
33503346 }
33513347
3352 local_dir = get_local_startup_path (local_dir);
3353 return elektroid_run (argc, argv, local_dir);
3354 }
3348 preferences_load (&preferences);
3349 if (local_dir)
3350 {
3351 g_free (preferences.local_dir);
3352 preferences.local_dir = get_local_startup_path (local_dir);
3353 }
3354
3355 ret = elektroid_run (argc, argv);
3356
3357 preferences_save (&preferences);
3358 preferences_free (&preferences);
3359
3360 return ret;
3361 }
0 /*
1 * local.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 <dirent.h>
21 #include <errno.h>
22 #include <libgen.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #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 *);
35
36 static gint local_copy_iterator (struct item_iterator *,
37 struct item_iterator *, gboolean);
38
39 const struct fs_operations FS_LOCAL_OPERATIONS = {
40 .fs = 0,
41 .readdir = local_read_dir,
42 .mkdir = local_mkdir,
43 .delete = local_delete,
44 .rename = local_rename,
45 .move = local_rename,
46 .copy = NULL,
47 .clear = NULL,
48 .swap = NULL,
49 .download = NULL,
50 .upload = NULL,
51 .getid = get_item_name,
52 .extension = NULL
53 };
54
55 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
230 return 0;
231 }
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 }
0 /*
1 * local.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 "utils.h"
22
23 struct local_iterator_data
24 {
25 DIR *dir;
26 gchar *path;
27 };
28
29 extern const struct fs_operations FS_LOCAL_OPERATIONS;
2525 #include "utils.h"
2626
2727 void
28 notifier_init (struct notifier *notifier, GSourceFunc refresh_dir,
29 GSourceFunc up_dir)
28 notifier_init (struct notifier *notifier, struct browser *browser)
3029 {
3130 notifier->fd = inotify_init ();
3231 notifier->wd = -1;
3332 notifier->event_size = sizeof (struct inotify_event) + PATH_MAX;
3433 notifier->event = malloc (notifier->event_size);
3534 notifier->running = 1;
36 notifier->refresh_dir = refresh_dir;
37 notifier->up_dir = up_dir;
35 notifier->browser = browser;
3836 }
3937
4038 void
4139 notifier_set_dir (struct notifier *notifier, gchar * path)
4240 {
41 debug_print (1, "Changing notifier path to %s...\n", path);
4342 if (notifier->fd < 0)
4443 {
4544 return;
5150 notifier->wd =
5251 inotify_add_watch (notifier->fd, path,
5352 IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_DELETE_SELF
54 | IN_MOVE_SELF);
53 | IN_MOVE_SELF | IN_MOVED_TO);
5554 }
5655
5756 void
7271 notifier_free (struct notifier *notifier)
7372 {
7473 free (notifier->event);
74 }
75
76 static gboolean
77 notifier_go_up (gpointer data)
78 {
79 struct browser *browser = data;
80 browser_go_up (NULL, browser);
81 return FALSE;
7582 }
7683
7784 gpointer
98105
99106 if (notifier->event->mask & IN_CREATE
100107 || notifier->event->mask & IN_DELETE
101 || notifier->event->mask & IN_MOVED_FROM)
108 || notifier->event->mask & IN_MOVED_FROM
109 || notifier->event->mask & IN_MOVED_TO)
102110 {
103111 debug_print (1, "Reloading local dir...\n");
104 g_idle_add (notifier->refresh_dir, NULL);
112 g_idle_add (browser_load_dir, notifier->browser);
105113 }
106114 else if (notifier->event->mask & IN_DELETE_SELF
107 || notifier->event->mask & IN_MOVE_SELF)
115 || notifier->event->mask & IN_MOVE_SELF ||
116 notifier->event->mask & IN_MOVED_TO)
108117 {
109118 debug_print (1, "Loading local parent dir...\n");
110 g_idle_add (notifier->up_dir, NULL);
119 g_idle_add (notifier_go_up, notifier->browser);
111120 }
112121 else
113122 {
1919
2020 #include <sys/inotify.h>
2121 #include <gtk/gtk.h>
22 #include "browser.h"
2223
2324 struct notifier
2425 {
2728 size_t event_size;
2829 struct inotify_event *event;
2930 gint running;
30 GSourceFunc refresh_dir;
31 GSourceFunc up_dir;
31 struct browser *browser;
3232 };
3333
34 void notifier_init (struct notifier *, GSourceFunc, GSourceFunc);
34 void notifier_init (struct notifier *, struct browser *);
3535
3636 void notifier_set_dir (struct notifier *, gchar *);
3737
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->fss & 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 g_object_unref (reader);
410 control->parts = 2;
411 goto get_payload;
412 }
413
414 if (!json_reader_read_member (reader, MAN_TAG_SAMPLE_REFS))
415 {
416 debug_print (1, "Member '%s' not found\n", MAN_TAG_SAMPLE_REFS);
417 control->parts = 2;
418 goto get_payload;
419 }
420
421 if (!json_reader_is_array (reader))
422 {
423 error_print ("Member '%s' is not an array. Continuing...\n",
424 MAN_TAG_SAMPLE_REFS);
425 control->parts = 2;
426 goto cleanup_reader;
427 }
428
429 elements = json_reader_count_elements (reader);
430 if (!elements)
431 {
432 debug_print (1, "No samples found\n");
433 control->parts = 2;
434 goto cleanup_reader;
435 }
436
437 sample = g_byte_array_new ();
438 control->parts = 2 + elements;
439 set_job_control_progress (control, 0.0);
440 for (i = 0; i < elements; i++, control->part++)
441 {
442 if (!json_reader_read_element (reader, i))
443 {
444 error_print ("Cannot read element %d. Continuing...\n", i);
445 continue;
446 }
447 if (!json_reader_read_member (reader, MAN_TAG_HASH))
448 {
449 error_print ("Cannot read member '%s'. Continuing...\n",
450 MAN_TAG_HASH);
451 continue;
452 }
453 hash = json_reader_get_int_value (reader);
454 json_reader_end_element (reader);
455
456 if (!json_reader_read_member (reader, MAN_TAG_SIZE))
457 {
458 error_print ("Cannot read member '%s'. Continuing...\n",
459 MAN_TAG_SIZE);
460 continue;
461 }
462 size = json_reader_get_int_value (reader);
463 json_reader_end_element (reader);
464
465 json_reader_end_element (reader);
466
467 sample_path =
468 connector_get_sample_path_from_hash_size (connector, hash, size);
469 if (!sample_path)
470 {
471 debug_print (1, "Sample not found. Skipping...\n");
472 continue;
473 }
474
475 debug_print (1, "Hash: %ld; size: %ld; path: %s\n", hash, size,
476 sample_path);
477 debug_print (1, "Getting sample %s...\n", sample_path);
478 g_byte_array_set_size (sample, 0);
479 if (download_sample (sample_path, sample, control, connector))
480 {
481 g_free (sample_path);
482 error_print ("Error while downloading sample. Continuing...\n");
483 continue;
484 }
485
486 wave = g_byte_array_new ();
487 if (sample_wave (sample, wave, control))
488 {
489 error_print
490 ("Error while converting sample to wave file. Continuing...\n");
491 g_byte_array_free (wave, TRUE);
492 g_free (sample_path);
493 continue;
494 }
495 g_free (control->data);
496 control->data = NULL;
497
498 pkg_resource = g_malloc (sizeof (struct package_resource));
499 pkg_resource->type = PKG_RES_TYPE_SAMPLE;
500 pkg_resource->data = wave;
501 pkg_resource->hash = hash;
502 pkg_resource->size = size;
503 pkg_resource->path = g_malloc (PATH_MAX);
504 snprintf (pkg_resource->path, PATH_MAX, "%s%s.wav", PKG_TAG_SAMPLES,
505 sample_path);
506 if (package_add_resource (pkg, pkg_resource, TRUE))
507 {
508 package_free_package_resource (pkg_resource);
509 error_print ("Error while packaging sample\n");
510 continue;
511 }
512 }
513
514 g_byte_array_free (sample, TRUE);
515 cleanup_reader:
516 g_object_unref (reader);
517 g_object_unref (parser);
518 get_payload:
519 g_byte_array_free (metadata, TRUE);
520 debug_print (1, "Getting payload from %s...\n", payload_path);
521 payload = g_byte_array_new ();
522 ret = download_data (payload_path, payload, control, connector);
523 if (ret)
524 {
525 error_print ("Error while downloading payload\n");
526 ret = -1;
527 }
528 else
529 {
530 pkg_resource = g_malloc (sizeof (struct package_resource));
531 pkg_resource->type = PKG_RES_TYPE_PAYLOAD;
532 pkg_resource->data = payload;
533 pkg_resource->path = strdup (pkg->name);
534 if (package_add_resource (pkg, pkg_resource, TRUE))
535 {
536 package_free_package_resource (pkg_resource);
537 ret = -1;
538 }
539 }
540 return ret;
541 }
542
543 gint
544 package_send_pkg_resources (struct package *pkg,
545 const gchar * payload_path,
546 struct job_control *control,
547 struct connector *connector,
548 fs_remote_file_op upload_data,
549 fs_remote_file_op upload_sample)
550 {
551 gint elements, i, ret = 0;
552 const gchar *file_type, *sample_path;
553 gint64 product_type;
554 JsonParser *parser;
555 JsonReader *reader;
556 GError *error;
557 zip_stat_t zstat;
558 zip_error_t zerror;
559 zip_file_t *zip_file;
560 GByteArray *wave, *raw;
561 struct package_resource *pkg_resource;
562
563 zip_error_init (&zerror);
564
565 parser = json_parser_new ();
566 if (!json_parser_load_from_data
567 (parser, (gchar *) pkg->manifest->data->data, pkg->manifest->data->len,
568 &error))
569 {
570 error_print ("Unable to parse stream: %s", error->message);
571 g_clear_error (&error);
572 ret = -1;
573 goto cleanup_parser;
574 }
575
576 reader = json_reader_new (json_parser_get_root (parser));
577 if (!reader)
578 {
579 ret = -1;
580 goto cleanup_parser;
581 }
582
583 if (!json_reader_read_member (reader, PKG_TAG_PAYLOAD))
584 {
585 error_print ("No '%s' found\n", PKG_TAG_PAYLOAD);
586 ret = -1;
587 goto cleanup_reader;
588 }
589 pkg->name = strdup (json_reader_get_string_value (reader));
590 json_reader_end_element (reader);
591
592 if (zip_stat (pkg->zip, pkg->name, ZIP_FL_ENC_STRICT, &zstat))
593 {
594 error_print ("Error while loading '%s': %s\n", MANIFEST_FILENAME,
595 zip_error_strerror (&zerror));
596 zip_error_fini (&zerror);
597 ret = -1;
598 goto cleanup_reader;
599 }
600
601 pkg_resource = g_malloc (sizeof (struct package_resource));
602 pkg_resource->type = PKG_RES_TYPE_PAYLOAD;
603 pkg_resource->data = g_byte_array_sized_new (zstat.size);
604 pkg_resource->path = strdup (pkg->name);
605 zip_file = zip_fopen (pkg->zip, pkg->name, 0);
606 zip_fread (zip_file, pkg_resource->data->data, zstat.size);
607 pkg_resource->data->len = zstat.size;
608 zip_fclose (zip_file);
609
610 pkg->resources = g_list_append (pkg->resources, pkg_resource);
611
612 control->parts = 129; // 128 sample slots and main.
613 control->part = 0;
614 ret = upload_data (payload_path, pkg_resource->data, control, connector);
615 if (ret)
616 {
617 error_print ("Error while uploading payload to '%s'\n", payload_path);
618 goto cleanup_reader;
619 }
620 control->part++;
621
622 if (!json_reader_read_member (reader, PKG_TAG_FIRMWARE_VERSION))
623 {
624 error_print ("No '%s' found\n", PKG_TAG_FIRMWARE_VERSION);
625 ret = -1;
626 goto cleanup_reader;
627 }
628 pkg->fw_version = strdup (json_reader_get_string_value (reader));
629 json_reader_end_element (reader);
630
631 if (!json_reader_read_member (reader, PKG_TAG_FILE_TYPE))
632 {
633 error_print ("No '%s' found\n", PKG_TAG_FILE_TYPE);
634 ret = -1;
635 goto cleanup_reader;
636 }
637 file_type = json_reader_get_string_value (reader);
638 json_reader_end_element (reader);
639
640 if (strcmp (file_type, PKG_VAL_FILE_TYPE_SND) == 0)
641 {
642 pkg->type = PKG_FILE_TYPE_SOUND;
643 }
644 else if (strcmp (file_type, PKG_VAL_FILE_TYPE_PRJ) == 0)
645 {
646 pkg->type = PKG_FILE_TYPE_PROJECT;
647 }
648 else
649 {
650 pkg->type = PKG_FILE_TYPE_NONE;
651 debug_print (1, "Invalid '%s': %s\n", PKG_TAG_FILE_TYPE, file_type);
652 }
653
654 if (!json_reader_read_member (reader, PKG_TAG_PRODUCT_TYPE))
655 {
656 error_print ("No '%s' found\n", PKG_TAG_PRODUCT_TYPE);
657 ret = 0;
658 goto cleanup_reader;
659 }
660 if (!json_reader_is_array (reader))
661 {
662 error_print ("Member '%s' is not an array\n", PKG_TAG_PRODUCT_TYPE);
663 ret = -1;
664 goto cleanup_reader;
665 }
666 if (!json_reader_count_elements (reader))
667 {
668 error_print ("No product types found\n");
669 ret = 0;
670 goto cleanup_reader;
671 }
672 if (!json_reader_read_element (reader, 0))
673 {
674 ret = -1;
675 goto cleanup_reader;
676 }
677 product_type = atoi (json_reader_get_string_value (reader));
678 debug_print (1, "ProductType: %ld\n", product_type);
679 if (pkg->device_desc->id != product_type)
680 {
681 debug_print (1, "Incompatible product type. Continuing...\n");
682 }
683 json_reader_end_element (reader);
684 json_reader_end_element (reader);
685
686 if (!(pkg->device_desc->fss & FS_SAMPLES))
687 {
688 ret = 0;
689 goto cleanup_reader;
690 }
691
692 if (!json_reader_read_member (reader, PKG_TAG_SAMPLES)
693 || !json_reader_is_array (reader))
694 {
695 debug_print (1, "No samples found\n");
696 control->parts = 1; // Only payload and it's done.
697 control->part = 0;
698 set_job_control_progress (control, 1.0);
699 goto cleanup_reader;
700 }
701
702 wave = g_byte_array_sized_new (zstat.size);
703 raw = g_byte_array_sized_new (MAX_PACKAGE_LEN);
704 elements = json_reader_count_elements (reader);
705 control->parts = elements + 1;
706 for (i = 0; i < elements; i++, control->parts++)
707 {
708 json_reader_read_element (reader, i);
709 json_reader_read_member (reader, PKG_TAG_FILE_NAME);
710 sample_path = json_reader_get_string_value (reader);
711 json_reader_end_element (reader);
712 json_reader_end_element (reader);
713
714 if (zip_stat (pkg->zip, sample_path, ZIP_FL_ENC_STRICT, &zstat))
715 {
716 error_print ("Error while loading '%s': %s\n",
717 MANIFEST_FILENAME, zip_error_strerror (&zerror));
718 zip_error_fini (&zerror);
719 ret = -1;
720 continue;
721 }
722
723 g_byte_array_set_size (wave, zstat.size);
724 zip_file = zip_fopen (pkg->zip, sample_path, 0);
725 zip_fread (zip_file, wave->data, zstat.size);
726 wave->len = zstat.size;
727 zip_fclose (zip_file);
728
729 raw->len = 0;
730 if (sample_raw (wave, raw, control))
731 {
732 continue;
733 }
734
735 pkg_resource = g_malloc (sizeof (struct package_resource));
736 pkg_resource->type = PKG_RES_TYPE_SAMPLE;
737 pkg_resource->data = g_byte_array_sized_new (raw->len);
738 pkg_resource->data->len = raw->len;
739 memcpy (pkg_resource->data->data, raw->data, raw->len);
740 pkg_resource->path = strdup (sample_path);
741
742 pkg->resources = g_list_append (pkg->resources, pkg_resource);
743
744 //We remove the "Samples" at the beggining of the full zip path.
745 ret =
746 upload_sample (&sample_path[7], pkg_resource->data, control,
747 connector);
748 g_free (control->data);
749 control->data = NULL;
750 if (ret)
751 {
752 error_print ("Error while uploading sample to '%s'\n",
753 &sample_path[7]);
754 continue;
755 }
756 }
757
758 g_byte_array_free (wave, TRUE);
759 g_byte_array_free (raw, TRUE);
760
761 cleanup_reader:
762 g_object_unref (reader);
763 cleanup_parser:
764 g_object_unref (parser);
765 return ret;
766 }
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 *);
0 /*
1 * preferences.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 <sys/stat.h>
21 #include <glib.h>
22 #include <json-glib/json-glib.h>
23 #include <wordexp.h>
24 #include "preferences.h"
25 #include "utils.h"
26
27 #define CONF_DIR "~/.config/elektroid"
28 #define CONF_FILE "/preferences.json"
29
30 #define MEMBER_AUTOPLAY "autoplay"
31 #define MEMBER_LOCALDIR "localDir"
32
33 gint
34 preferences_save (struct preferences *preferences)
35 {
36 size_t n;
37 gchar *preferences_path;
38 JsonBuilder *builder;
39 JsonGenerator *gen;
40 JsonNode *root;
41 gchar *json;
42
43 preferences_path = get_expanded_dir (CONF_DIR);
44 if (g_mkdir_with_parents (preferences_path,
45 S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH |
46 S_IXOTH))
47 {
48 return 1;
49 }
50
51 n = PATH_MAX - strlen (preferences_path) - 1;
52 strncat (preferences_path, CONF_FILE, n);
53 preferences_path[PATH_MAX - 1] = 0;
54
55 debug_print (1, "Saving preferences to '%s'...\n", preferences_path);
56
57 builder = json_builder_new ();
58
59 json_builder_begin_object (builder);
60
61 json_builder_set_member_name (builder, MEMBER_AUTOPLAY);
62 json_builder_add_boolean_value (builder, preferences->autoplay);
63
64 json_builder_set_member_name (builder, MEMBER_LOCALDIR);
65 json_builder_add_string_value (builder, preferences->local_dir);
66
67 json_builder_end_object (builder);
68
69 gen = json_generator_new ();
70 root = json_builder_get_root (builder);
71 json_generator_set_root (gen, root);
72 json = json_generator_to_data (gen, NULL);
73
74 save_file_char (preferences_path, (guint8 *) json, strlen (json));
75
76 g_free (json);
77 json_node_free (root);
78 g_object_unref (gen);
79 g_object_unref (builder);
80 g_free (preferences_path);
81
82 return 0;
83 }
84
85 gint
86 preferences_load (struct preferences *preferences)
87 {
88 size_t n;
89 GError *error;
90 JsonReader *reader;
91 JsonParser *parser = json_parser_new ();
92 gchar *preferences_file = get_expanded_dir (CONF_DIR CONF_FILE);
93
94 error = NULL;
95 json_parser_load_from_file (parser, preferences_file, &error);
96 if (error)
97 {
98 error_print ("Error wile loading preferences from `%s': %s\n",
99 CONF_DIR CONF_FILE, error->message);
100 g_error_free (error);
101 g_object_unref (parser);
102 preferences->autoplay = TRUE;
103 preferences->local_dir = get_expanded_dir ("~");
104 return 0;
105 }
106
107 reader = json_reader_new (json_parser_get_root (parser));
108 json_reader_read_member (reader, MEMBER_AUTOPLAY);
109 preferences->autoplay = json_reader_get_boolean_value (reader);
110 json_reader_end_member (reader);
111 json_reader_read_member (reader, MEMBER_LOCALDIR);
112 preferences->local_dir = malloc (PATH_MAX);
113 n = PATH_MAX - 1;
114 strncpy (preferences->local_dir, json_reader_get_string_value (reader), n);
115 preferences->local_dir[PATH_MAX - 1] = 0;
116 json_reader_end_member (reader);
117 g_object_unref (reader);
118 g_object_unref (parser);
119
120 g_free (preferences_file);
121
122 return 0;
123 }
124
125 void
126 preferences_free (struct preferences *preferences)
127 {
128 g_free (preferences->local_dir);
129 }
0 /*
1 * preferences.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 #include <glib.h>
21
22 struct preferences
23 {
24 gboolean autoplay;
25 gchar *local_dir;
26 };
27
28 gint preferences_save (struct preferences *);
29
30 gint preferences_load (struct preferences *);
31
32 void preferences_free (struct preferences *);
2222 #include <samplerate.h>
2323 #include <inttypes.h>
2424 #include "sample.h"
25 #include "utils.h"
26
27 size_t
28 sample_save (GArray * sample, gchar * path)
25
26 #define JUNK_CHUNK_ID "JUNK"
27 #define SMPL_CHUNK_ID "smpl"
28
29 struct smpl_chunk_data
30 {
31 guint32 manufacturer;
32 guint32 product;
33 guint32 sample_period;
34 guint32 midi_unity_note;
35 guint32 midi_pitch_fraction;
36 guint32 smpte_format;
37 guint32 smpte_offset;
38 guint32 num_sampler_loops;
39 guint32 sampler_data;
40 struct sample_loop
41 {
42 guint32 cue_point_id;
43 guint32 type;
44 guint32 start;
45 guint32 end;
46 guint32 fraction;
47 guint32 play_count;
48 } sample_loop;
49 };
50
51 struct g_byte_array_io_data
52 {
53 GByteArray *array;
54 guint pos;
55 };
56
57 static const guint8 JUNK_CHUNK_DATA[] = {
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61 0, 0, 0, 0
62 };
63
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
78 static sf_count_t
79 get_filelen_byte_array_io (void *user_data)
80 {
81 struct g_byte_array_io_data *data = user_data;
82 return data->array->len;
83 }
84
85 static sf_count_t
86 seek_byte_array_io (sf_count_t offset, int whence, void *user_data)
87 {
88 struct g_byte_array_io_data *data = user_data;
89 switch (whence)
90 {
91 case SEEK_SET:
92 data->pos = offset;
93 break;
94 case SEEK_CUR:
95 data->pos = data->pos + offset;
96 break;
97 case SEEK_END:
98 data->pos = data->array->len + offset;
99 break;
100 default:
101 break;
102 };
103
104 if (data->pos > data->array->len)
105 {
106 g_byte_array_set_size (data->array, data->pos);
107 }
108 return data->pos;
109 }
110
111 static sf_count_t
112 read_byte_array_io (void *ptr, sf_count_t count, void *user_data)
113 {
114 struct g_byte_array_io_data *data = user_data;
115 if (data->pos + count > data->array->len)
116 {
117 count = data->array->len - data->pos;
118 }
119 memcpy (ptr, data->array->data + data->pos, count);
120 data->pos += count;
121 return count;
122 }
123
124 static sf_count_t
125 write_byte_array_io (const void *ptr, sf_count_t count, void *user_data)
126 {
127 struct g_byte_array_io_data *data = user_data;
128
129 if (data->pos >= data->array->len)
130 {
131 g_byte_array_set_size (data->array, data->pos);
132 }
133
134 if (data->pos + count > data->array->len)
135 {
136 g_byte_array_set_size (data->array, data->pos + count);
137 }
138
139 memcpy (data->array->data + data->pos, (guint8 *) ptr, count);
140 data->pos += count;
141 return count;
142 }
143
144 static sf_count_t
145 tell_byte_array_io (void *user_data)
146 {
147 struct g_byte_array_io_data *data = user_data;
148 return data->pos;
149 }
150
151 static gint
152 sample_wave_data (GByteArray * sample,
153 struct job_control *control,
154 struct g_byte_array_io_data *wave)
29155 {
30156 SF_INFO sf_info;
31157 SNDFILE *sndfile;
32 int total;
33
34 debug_print (1, "Saving file %s...\n", path);
35
36 sf_info.format = 0;
37 sf_info.samplerate = 48000;
158 sf_count_t frames, total;
159 struct SF_CHUNK_INFO junk_chunk_info;
160 struct SF_CHUNK_INFO smpl_chunk_info;
161 struct smpl_chunk_data smpl_chunk_data;
162 struct sample_loop_data *sample_loop_data = control->data;
163
164 g_byte_array_set_size (wave->array, sample->len + 1024); //We need space for the headers.
165 wave->array->len = 0;
166
167 debug_print (1, "Loop start at %d; loop end at %d\n",
168 sample_loop_data->start, sample_loop_data->end);
169
170 memset (&sf_info, 0, sizeof (sf_info));
171 sf_info.samplerate = ELEKTRON_SAMPLE_RATE;
38172 sf_info.channels = 1;
39173 sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
40 sndfile = sf_open (path, SFM_WRITE, &sf_info);
174 sndfile = sf_open_virtual (&G_BYTE_ARRAY_IO, SFM_WRITE, &sf_info, wave);
41175 if (!sndfile)
42176 {
43177 error_print ("%s\n", sf_strerror (sndfile));
44178 return -1;
45179 }
46180
47 total = sf_write_short (sndfile, (short *) sample->data, sample->len);
181 strcpy (junk_chunk_info.id, JUNK_CHUNK_ID);
182 junk_chunk_info.id_size = strlen (JUNK_CHUNK_ID);
183 junk_chunk_info.datalen = sizeof (JUNK_CHUNK_DATA);
184 junk_chunk_info.data = (void *) JUNK_CHUNK_DATA;
185 if (sf_set_chunk (sndfile, &junk_chunk_info) != SF_ERR_NO_ERROR)
186 {
187 error_print ("%s\n", sf_strerror (sndfile));
188 }
189
190 smpl_chunk_data.manufacturer = 0;
191 smpl_chunk_data.product = 0;
192 smpl_chunk_data.sample_period = 1000000000 / ELEKTRON_SAMPLE_RATE;
193 smpl_chunk_data.midi_unity_note = 60;
194 smpl_chunk_data.midi_pitch_fraction = 0;
195 smpl_chunk_data.smpte_format = 0;
196 smpl_chunk_data.smpte_offset = 0;
197 smpl_chunk_data.num_sampler_loops = 1;
198 smpl_chunk_data.sampler_data = 0;
199 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;
203 smpl_chunk_data.sample_loop.fraction = 0;
204 smpl_chunk_data.sample_loop.play_count = 0;
205
206 strcpy (smpl_chunk_info.id, SMPL_CHUNK_ID);
207 smpl_chunk_info.id_size = strlen (SMPL_CHUNK_ID);
208 smpl_chunk_info.datalen = sizeof (struct smpl_chunk_data);
209 smpl_chunk_info.data = &smpl_chunk_data;
210 if (sf_set_chunk (sndfile, &smpl_chunk_info) != SF_ERR_NO_ERROR)
211 {
212 error_print ("%s\n", sf_strerror (sndfile));
213 }
214
215 frames = sample->len >> 1;
216 total = sf_write_short (sndfile, (gint16 *) sample->data, frames);
48217
49218 sf_close (sndfile);
50219
51 return total;
220 if (total != frames)
221 {
222 error_print ("Unexpected frames while writing to sample (%ld != %ld)\n",
223 total, frames);
224 return -1;
225 }
226
227 return 0;
228 }
229
230 gint
231 sample_wave (GByteArray * sample, GByteArray * wave,
232 struct job_control *control)
233 {
234 struct g_byte_array_io_data data;
235 data.pos = 0;
236 data.array = wave;
237 return sample_wave_data (sample, control, &data);
238 }
239
240 gint
241 sample_save (const gchar * path, GByteArray * sample,
242 struct job_control *control)
243 {
244 GByteArray *wave = g_byte_array_new ();
245 gint ret = sample_wave (sample, wave, control);
246 if (!ret)
247 {
248 ret = save_file (path, wave, control);
249 }
250 g_byte_array_free (wave, TRUE);
251 return ret;
52252 }
53253
54254 static void
71271 }
72272 }
73273
74 size_t
75 sample_load (GArray * sample, GMutex * mutex, gint * frames, gchar * path,
76 gboolean * active, void (*progress) (gdouble))
274 static gint
275 sample_raw_data (struct g_byte_array_io_data *wave,
276 struct job_control *control, GByteArray * sample,
277 guint * frames)
77278 {
78279 SF_INFO sf_info;
79280 SNDFILE *sndfile;
80281 SRC_DATA src_data;
81282 SRC_STATE *src_state;
82 short *buffer_input;
83 short *buffer_input_multi;
84 short *buffer_input_mono;
85 short *buffer_s;
86 float *buffer_f;
87 int err;
88 int resampled_buffer_len;
89 int f, frames_read;
90 gboolean load_active;
91
92 debug_print (1, "Loading file %s...\n", path);
93
94 if (mutex)
95 {
96 g_mutex_lock (mutex);
97 }
98 g_array_set_size (sample, 0);
99 if (mutex)
100 {
101 g_mutex_unlock (mutex);
283 struct SF_CHUNK_INFO chunk_info;
284 SF_CHUNK_ITERATOR *chunk_iter;
285 gint16 *buffer_input;
286 gint16 *buffer_input_multi;
287 gint16 *buffer_input_mono;
288 gint16 *buffer_s;
289 gfloat *buffer_f;
290 gint err;
291 gint resampled_buffer_len;
292 gint f, frames_read;
293 gboolean active;
294 struct sample_loop_data *sample_loop_data;
295 struct smpl_chunk_data smpl_chunk_data;
296
297 if (control)
298 {
299 g_mutex_lock (&control->mutex);
300 }
301 g_byte_array_set_size (sample, 0);
302 if (control)
303 {
304 g_mutex_unlock (&control->mutex);
102305 }
103306
104307 sf_info.format = 0;
105 sndfile = sf_open (path, SFM_READ, &sf_info);
308 sndfile = sf_open_virtual (&G_BYTE_ARRAY_IO, SFM_READ, &sf_info, wave);
106309 if (!sndfile)
107310 {
108311 error_print ("%s\n", sf_strerror (sndfile));
109312 return -1;
110313 }
314
315 strcpy (chunk_info.id, SMPL_CHUNK_ID);
316 chunk_info.id_size = strlen (SMPL_CHUNK_ID);
317 chunk_iter = sf_get_chunk_iterator (sndfile, &chunk_info);
318 sample_loop_data = malloc (sizeof (struct sample_loop_data));
319 if (chunk_iter)
320 {
321 chunk_info.datalen = sizeof (struct smpl_chunk_data);
322 chunk_info.data = &smpl_chunk_data;
323 sf_get_chunk_data (chunk_iter, &chunk_info);
324
325 sample_loop_data->start = le32toh (smpl_chunk_data.sample_loop.start);
326 sample_loop_data->end = le32toh (smpl_chunk_data.sample_loop.end);
327 }
328 else
329 {
330 sample_loop_data->start = 0;
331 sample_loop_data->end = 0;
332 }
333
334 control->data = sample_loop_data;
111335
112336 //Set scale factor. See http://www.mega-nerd.com/libsndfile/api.html#note2
113337 if ((sf_info.format & SF_FORMAT_FLOAT) == SF_FORMAT_FLOAT ||
119343 }
120344
121345 buffer_input_multi =
122 malloc (LOAD_BUFFER_LEN * sf_info.channels * sizeof (short));
123 buffer_input_mono = malloc (LOAD_BUFFER_LEN * sizeof (short));
124
125 buffer_f = malloc (LOAD_BUFFER_LEN * sizeof (float));
346 malloc (LOAD_BUFFER_LEN * sf_info.channels * sizeof (gint16));
347 buffer_input_mono = malloc (LOAD_BUFFER_LEN * sizeof (gint16));
348
349 buffer_f = malloc (LOAD_BUFFER_LEN * sizeof (gfloat));
126350 src_data.data_in = buffer_f;
127 src_data.src_ratio = 48000.0 / sf_info.samplerate;
351 src_data.src_ratio = ((double) ELEKTRON_SAMPLE_RATE) / sf_info.samplerate;
128352
129353 resampled_buffer_len = LOAD_BUFFER_LEN * src_data.src_ratio;
130 buffer_s = malloc (resampled_buffer_len * sizeof (short));
131 src_data.data_out = malloc (resampled_buffer_len * sizeof (float));
354 buffer_s = malloc (resampled_buffer_len * sizeof (gint16));
355 src_data.data_out = malloc (resampled_buffer_len * sizeof (gfloat));
132356
133357 src_state = src_new (SRC_SINC_BEST_QUALITY, 1, &err);
134358 if (err)
141365 *frames = sf_info.frames * src_data.src_ratio;
142366 }
143367
144 debug_print (2, "Loading sample (%" PRId64 ")...\n", sf_info.frames);
368 if (ELEKTRON_SAMPLE_RATE != sf_info.samplerate)
369 {
370 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;
374 debug_print (2, "Loop start at %d, loop end at %d after resampling\n",
375 sample_loop_data->start, sample_loop_data->end);
376 }
377
378 debug_print (2, "Loading sample (%" PRId64 " frames)...\n", sf_info.frames);
145379
146380 f = 0;
147 if (mutex)
148 {
149 g_mutex_lock (mutex);
150 }
151 load_active = (!active || *active);
152 if (mutex)
153 {
154 g_mutex_unlock (mutex);
155 }
156 while (f < sf_info.frames && load_active)
381 if (control)
382 {
383 g_mutex_lock (&control->mutex);
384 active = control->active;
385 g_mutex_unlock (&control->mutex);
386 }
387 else
388 {
389 active = TRUE;
390 }
391
392 while (f < sf_info.frames && active)
157393 {
158394 debug_print (2, "Loading buffer...\n");
159395
182418 buffer_input = buffer_input_mono;
183419 }
184420
185 if (sf_info.samplerate == 48000)
186 {
187 if (mutex)
421 if (sf_info.samplerate == ELEKTRON_SAMPLE_RATE)
422 {
423 if (control)
188424 {
189 g_mutex_lock (mutex);
425 g_mutex_lock (&control->mutex);
190426 }
191 g_array_append_vals (sample, buffer_input, frames_read);
192 if (mutex)
427 g_byte_array_append (sample, (guint8 *) buffer_input,
428 frames_read << 1);
429 if (control)
193430 {
194 g_mutex_unlock (mutex);
431 g_mutex_unlock (&control->mutex);
195432 }
196433 }
197434 else
207444 }
208445 src_float_to_short_array (src_data.data_out, buffer_s,
209446 src_data.output_frames_gen);
210 if (mutex)
447 if (control)
211448 {
212 g_mutex_lock (mutex);
449 g_mutex_lock (&control->mutex);
213450 }
214 g_array_append_vals (sample, buffer_s, src_data.output_frames_gen);
215 if (mutex)
451 g_byte_array_append (sample, (guint8 *) buffer_s,
452 src_data.output_frames_gen << 1);
453 if (control)
216454 {
217 g_mutex_unlock (mutex);
455 g_mutex_unlock (&control->mutex);
218456 }
219457 }
220458
221 if (progress)
222 {
223 progress (f * 1.0 / sf_info.frames);
224 }
225
226 if (mutex)
227 {
228 g_mutex_lock (mutex);
229 }
230 load_active = (!active || *active);
231 if (mutex)
232 {
233 g_mutex_unlock (mutex);
459 if (control)
460 {
461 control->callback (f * 1.0 / sf_info.frames);
462 g_mutex_lock (&control->mutex);
463 active = control->active;
464 g_mutex_unlock (&control->mutex);
234465 }
235466 }
236467
242473 src_strerror (err));
243474 }
244475
245 if (mutex)
246 {
247 g_mutex_lock (mutex);
248 }
249 if (!active || *active)
250 {
251 if (progress)
252 {
253 progress (1.0);
254 }
255 }
256 else
257 {
258 g_array_set_size (sample, 0);
259 }
260 if (mutex)
261 {
262 g_mutex_unlock (mutex);
476 if (control)
477 {
478 g_mutex_lock (&control->mutex);
479
480 if (control->active)
481 {
482 control->callback (1.0);
483 }
484 else
485 {
486 g_byte_array_set_size (sample, 0);
487 }
488
489 g_mutex_unlock (&control->mutex);
263490 }
264491
265492 cleanup:
271498
272499 sf_close (sndfile);
273500
274 return sample->len;
275 }
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)
512 {
513 struct g_byte_array_io_data data;
514 data.pos = 0;
515 data.array = wave;
516 return sample_raw_data (&data, control, sample, frames);
517 }
518
519 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 }
2020 #include <glib.h>
2121 #include <sys/types.h>
2222 #include <sys/stat.h>
23 #include "utils.h"
2324
24 #define LOAD_BUFFER_LEN 4800
25 #ifndef SAMPLE_H
26 #define SAMPLE_H
2527
26 size_t sample_save (GArray *, gchar *);
28 #define LOAD_BUFFER_LEN 4800 // In guint16 frames; 9600 B; 0.1 ms
2729
28 size_t sample_load (GArray *, GMutex *, gboolean *, gchar *, gint *,
29 void (*)(gdouble));
30 gint sample_wave (GByteArray *, GByteArray *, struct job_control *);
31
32 gint sample_raw (GByteArray *, GByteArray *, struct job_control *);
33
34 gint sample_save (const gchar *, GByteArray *, struct job_control *);
35
36 gint sample_load (const gchar *, GByteArray *, struct job_control *);
37
38 gint sample_load_with_frames (const gchar *, GByteArray *,
39 struct job_control *, guint *);
40
41 #endif
1717 * along with Elektroid. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20 #include <glib.h>
2120 #include <stdio.h>
2221 #include <wordexp.h>
22 #include <errno.h>
2323 #include "utils.h"
2424
2525 #define DEBUG_SHORT_HEX_LEN 64
2626 #define DEBUG_FULL_HEX_THRES 3
2727
28 #define REG_TYPE "elektroid-wave-symbolic"
29 #define DIR_TYPE "folder-visiting-symbolic"
28 #define KIB 1024
3029
3130 gint debug_level;
3231
148147 int i = namelen;
149148 const gchar *ext = &name[namelen];
150149
151 while (*(ext - 1) != '.' && i > 0)
150 while (i > 0 && *(ext - 1) != '.')
152151 {
153152 ext--;
154153 i--;
164163 }
165164 }
166165
167 char
168 get_type_from_inventory_icon (const gchar * icon)
169 {
170 gchar type;
171
172 if (strcmp (icon, REG_TYPE) == 0)
173 {
174 type = ELEKTROID_FILE;
175 }
176 else
177 {
178 type = ELEKTROID_DIR;
179 }
180 return type;
181 }
182
183 const gchar *
184 get_inventory_icon_from_type (char type)
185 {
186 const gchar *icon;
187
188 if (type == ELEKTROID_FILE)
189 {
190 icon = REG_TYPE;
191 }
192 else
193 {
194 icon = DIR_TYPE;
195 }
196 return icon;
166 gchar *
167 get_expanded_dir (const char *exp)
168 {
169 wordexp_t exp_result;
170 size_t n;
171 gchar *exp_dir = malloc (PATH_MAX);
172
173 wordexp (exp, &exp_result, 0);
174 n = PATH_MAX - 1;
175 strncpy (exp_dir, exp_result.we_wordv[0], n);
176 exp_dir[PATH_MAX - 1] = 0;
177 wordfree (&exp_result);
178
179 return exp_dir;
197180 }
198181
199182 char *
201184 {
202185 DIR *dir;
203186 gchar *startup_path = NULL;
204 wordexp_t exp_result;
205187
206188 if (local_dir)
207189 {
213195 }
214196 else
215197 {
216 error_print ("Unable to open dir %s\n", local_dir);
198 error_print ("Unable to open dir '%s'\n", local_dir);
217199 }
218200 closedir (dir);
219201 }
220202
221203 if (!startup_path)
222204 {
223 wordexp ("~", &exp_result, 0);
224 startup_path = malloc (PATH_MAX);
225 strcpy (startup_path, exp_result.we_wordv[0]);
226 wordfree (&exp_result);
227 }
228
229 debug_print (1, "Using %s as local dir...\n", startup_path);
205 startup_path = get_expanded_dir ("~");
206 }
207
208 debug_print (1, "Using '%s' as local dir...\n", startup_path);
230209
231210 return startup_path;
232211 }
212
213 void
214 free_msg (gpointer msg)
215 {
216 g_byte_array_free ((GByteArray *) msg, TRUE);
217 }
218
219 gchar *
220 get_item_name (struct item *item)
221 {
222 return strdup (item->name);
223 }
224
225 gchar *
226 get_item_index (struct item *item)
227 {
228 gchar *index;
229
230 if (item->type == ELEKTROID_DIR)
231 {
232 index = get_item_name (item);
233 }
234 else
235 {
236 index = malloc (LABEL_MAX);
237 snprintf (index, LABEL_MAX, "%d", item->index);
238 }
239
240 return index;
241 }
242
243 guint
244 next_item_iterator (struct item_iterator *iter)
245 {
246 return iter->next (iter);
247 }
248
249 void
250 free_item_iterator (struct item_iterator *iter)
251 {
252 if (iter->free)
253 {
254 iter->free (iter->data);
255 }
256 }
257
258 gint
259 copy_item_iterator (struct item_iterator *dst, struct item_iterator *src,
260 gboolean cached)
261 {
262 return src->copy (dst, src, cached);
263 }
264
265 gint
266 load_file (const char *path, GByteArray * array, struct job_control *control)
267 {
268 FILE *file;
269 long size;
270 gint res;
271
272 file = fopen (path, "rb");
273
274 if (!file)
275 {
276 return -errno;
277 }
278
279 res = 0;
280
281 if (fseek (file, 0, SEEK_END))
282 {
283 error_print ("Unexpected value\n");
284 res = -errno;
285 goto end;
286 }
287
288 size = ftell (file);
289 rewind (file);
290
291 g_byte_array_set_size (array, size);
292
293 if (fread (array->data, 1, size, file) == size)
294 {
295 debug_print (1, "%zu bytes read\n", size);
296 }
297 else
298 {
299 error_print ("Error while reading from file %s\n", path);
300 res = -errno;
301 }
302
303 end:
304 fclose (file);
305 return res;
306 }
307
308 gint
309 save_file_char (const gchar * path, const guint8 * data, ssize_t len)
310 {
311 gint res;
312 long bytes;
313 FILE *file;
314
315 file = fopen (path, "w");
316
317 if (!file)
318 {
319 return -errno;
320 }
321
322 debug_print (1, "Saving file %s...\n", path);
323
324 res = 0;
325 bytes = fwrite (data, 1, len, file);
326 if (bytes == len)
327 {
328 debug_print (1, "%zu bytes written\n", bytes);
329 }
330 else
331 {
332 error_print ("Error while writing to file %s\n", path);
333 res = -EIO;
334 }
335
336 fclose (file);
337
338 return res;
339 }
340
341 gint
342 save_file (const gchar * path, GByteArray * array,
343 struct job_control *control)
344 {
345 return save_file_char (path, array->data, array->len);
346 }
347
348 gchar *
349 get_human_size (guint size, gboolean with_space)
350 {
351 gchar *label = malloc (LABEL_MAX);
352 gchar *space = with_space ? " " : "";
353
354 if (size < KIB)
355 {
356 snprintf (label, LABEL_MAX, "%d%sB", size, space);
357 }
358 else if (size < KIB * KIB)
359 {
360 snprintf (label, LABEL_MAX, "%.2f%sKiB", size / (double) KIB, space);
361 }
362 else if (size < KIB * KIB * KIB)
363 {
364 snprintf (label, LABEL_MAX, "%.2f%sMiB", size / (double) (KIB * KIB),
365 space);
366 }
367 else
368 {
369 snprintf (label, LABEL_MAX, "%.2f%sGiB",
370 size / (double) (KIB * KIB * KIB), space);
371 }
372
373 return label;
374 }
375
376 void
377 set_job_control_progress (struct job_control *control, gdouble p)
378 {
379 gdouble v = (double) control->part / control->parts + p / control->parts;
380 control->callback (v);
381 }
1818 */
1919
2020 #include <stdio.h>
21 #include <glib.h>
22
23 #ifndef UTILS_H
24 #define UTILS_H
2125
2226 #define LABEL_MAX 128
2327
24 #define ELEKTROID_FILE 'F'
25 #define ELEKTROID_DIR 'D'
26 #define ELEKTROID_NONE '?'
28 #define ELEKTRON_LOOP_TYPE 0x7f
29 #define ELEKTRON_SAMPLE_RATE 48000
2730
2831 #define debug_print(level, format, ...) if (level <= debug_level) fprintf(stderr, "DEBUG:" __FILE__ ":%d:(%s): " format, __LINE__, __FUNCTION__, ## __VA_ARGS__)
2932 #define error_print(format, ...) fprintf(stderr, "\x1b[31mERROR:" __FILE__ ":%d:(%s): " format "\x1b[m", __LINE__, __FUNCTION__, ## __VA_ARGS__)
33
34 enum item_type
35 {
36 ELEKTROID_NONE = 0,
37 ELEKTROID_FILE = 'F',
38 ELEKTROID_DIR = 'D'
39 };
40
41 struct item_iterator;
42
43 typedef guint (*iterator_next) (struct item_iterator *);
44
45 typedef void (*iterator_free) (void *);
46
47 typedef gint (*iterator_copy) (struct item_iterator *,
48 struct item_iterator *, gboolean);
49
50 struct item
51 {
52 gchar *name;
53 guint32 size;
54 gint32 index;
55 enum item_type type;
56 };
57
58 struct item_iterator
59 {
60 iterator_next next;
61 iterator_free free;
62 iterator_copy copy;
63 void *data;
64 struct item item;
65 };
66
67 typedef void (*job_control_callback) (gdouble);
68
69 struct job_control
70 {
71 gboolean active;
72 GMutex mutex;
73 job_control_callback callback;
74 gint parts;
75 gint part;
76 void *data;
77 };
78
79 struct sample_loop_data
80 {
81 gint32 start;
82 gint32 end;
83 };
84
85 typedef gint (*fs_init_iter_func) (struct item_iterator *, const gchar *,
86 void *);
87
88 typedef gint (*fs_path_func) (const gchar *, void *);
89
90 typedef gint (*fs_src_dst_func) (const gchar *, const gchar *, void *);
91
92 typedef gint (*fs_remote_file_op) (const gchar *, GByteArray *,
93 struct job_control *, void *);
94
95 typedef gchar *(*fs_get_item_id) (struct item *);
96
97 typedef gint (*fs_local_file_op) (const gchar *, GByteArray *,
98 struct job_control *);
99
100 struct fs_operations
101 {
102 gint fs;
103 fs_init_iter_func readdir;
104 fs_path_func mkdir;
105 fs_path_func delete;
106 fs_src_dst_func rename;
107 fs_src_dst_func move;
108 fs_src_dst_func copy;
109 fs_path_func clear;
110 fs_src_dst_func swap;
111 fs_remote_file_op download;
112 fs_remote_file_op upload;
113 fs_get_item_id getid;
114 fs_local_file_op save;
115 fs_local_file_op load;
116 const gchar *extension;
117 };
30118
31119 extern int debug_level;
32120
42130
43131 gchar get_type_from_inventory_icon (const gchar *);
44132
45 const gchar *get_inventory_icon_from_type (gchar);
133 gchar *get_expanded_dir (const char *);
46134
47135 gchar *get_local_startup_path (const gchar *);
136
137 void free_msg (gpointer);
138
139 gchar *get_item_name (struct item *);
140
141 gchar *get_item_index (struct item *);
142
143 guint next_item_iterator (struct item_iterator *);
144
145 void free_item_iterator (struct item_iterator *);
146
147 gint copy_item_iterator (struct item_iterator *, struct item_iterator *,
148 gboolean);
149
150 gint load_file (const char *, GByteArray *, struct job_control *);
151
152 gint save_file (const char *, GByteArray *, struct job_control *);
153
154 gint save_file_char (const gchar *, const guint8 *, ssize_t);
155
156 gchar *get_human_size (guint, gboolean);
157
158 void set_job_control_progress (struct job_control *, gdouble);
159
160 #endif
0 TESTS=full_test.sh
0 TESTS = sample_fs_tests.sh data_fs_tests.sh
11
22 EXTRA_DIST = \
33 $(TESTS) \
0 #!/usr/bin/env bash
1
2 function get_sound_n_with_id () {
3 s="sound$1"
4 echo "${!s}" | sed "s/^F $1 0012/F $2 007e/"
5 }
6
7 echo "Getting devices..."
8 DEVICE=$($ecli ld | head -n 1 | awk '{print $1}')
9 [ -z "$DEVICE" ] && echo "No device found" && exit 0
10 echo "Using device $DEVICE..."
11
12 sound1=$($ecli ls-data $DEVICE:/soundbanks/A | grep "^F 1")
13 nsound1=$(get_sound_n_with_id 1 64)
14
15 sound2=$($ecli ls-data $DEVICE:/soundbanks/A | grep "^F 2")
16
17 echo "Testing data copy..."
18 $ecli cp-data $DEVICE:/soundbanks/A/1 $DEVICE:/soundbanks/H/64
19 [ $? -ne 0 ] && exit 1
20 $ecli cp-data $DEVICE:/soundbanks/A/2 $DEVICE:/soundbanks/H/63
21 [ $? -ne 0 ] && exit 1
22 output=$($ecli ls-data $DEVICE:/soundbanks/H)
23 actual=$(echo "$output" | grep "^F 64")
24 expected=$(get_sound_n_with_id 1 64)
25 [ "$actual" != "$expected" ] && exit 1
26 actual=$(echo "$output" | grep "^F 63")
27 expected=$(get_sound_n_with_id 2 63)
28 [ "$actual" != "$expected" ] && exit 1
29
30 echo "Testing data move..."
31 $ecli mv-data $DEVICE:/soundbanks/H/64 $DEVICE:/soundbanks/H/62
32 [ $? -ne 0 ] && exit 1
33 output=$($ecli ls-data $DEVICE:/soundbanks/H)
34 actual=$(echo "$output" | grep "^F 62")
35 expected=$(get_sound_n_with_id 1 62)
36 [ "$actual" != "$expected" ] && exit 1
37 actual=$(echo "$output" | grep "^F 64")
38 [ -n "$actual" ] && exit 1
39
40 echo "Testing data swap..."
41 $ecli sw-data $DEVICE:/soundbanks/H/62 $DEVICE:/soundbanks/H/63
42 [ $? -ne 0 ] && exit 1
43 output=$($ecli ls-data $DEVICE:/soundbanks/H)
44 actual=$(echo "$output" | grep "^F 62")
45 expected=$(get_sound_n_with_id 2 62)
46 [ "$actual" != "$expected" ] && exit 1
47 actual=$(echo "$output" | grep "^F 63")
48 expected=$(get_sound_n_with_id 1 63)
49 [ "$actual" != "$expected" ] && exit 1
50
51 echo "Testing data clear..."
52 $ecli cl-data $DEVICE:/soundbanks/H/63
53 [ $? -ne 0 ] && exit 1
54 $ecli cl-data $DEVICE:/soundbanks/H/62
55 [ $? -ne 0 ] && exit 1
56 output=$($ecli ls-data $DEVICE:/soundbanks/H)
57 [ $(echo "$output" | grep "^F 62" | wc -l) -ne 0 ] && exit 1
58 [ $(echo "$output" | grep "^F 63" | wc -l) -ne 0 ] && exit 1
59
60 echo "Testing upload..."
61 $ecli ul-data $srcdir/res/SOUND.dtdata $DEVICE:/soundbanks/H
62 [ $? -ne 0 ] && exit 1
63 id=$($ecli ls-data $DEVICE:/soundbanks/H | grep 'SOUND$' | awk '{print $2}')
64
65 echo "Testing download..."
66 $ecli dl-data $DEVICE:/soundbanks/H/$id
67 [ $? -ne 0 ] && exit 1
68 ls "SOUND.dtdata"
69 cksum SOUND.dtdata
70 cksum $srcdir/res/SOUND.dtdata
71 actual_cksum="$(cksum SOUND.dtdata | awk '{print $1}')"
72 [ "$actual_cksum" != "$(cksum $srcdir/res/SOUND.dtdata | awk '{print $1}')" ] && exit 1
73 rm SOUND.dtdata
74 [ $? -ne 0 ] && exit 1
75 $ecli cl-data $DEVICE:/soundbanks/H/$id
76 [ $? -ne 0 ] && exit 1
77
78 echo "Testing upload..."
79 $ecli ul-data $srcdir/res/SOUND.dtdata $DEVICE:/soundbanks/H
80 [ $? -ne 0 ] && exit 1
81 id=$($ecli ls-data $DEVICE:/soundbanks/H/256 | grep 'SOUND$' | awk '{print $2}')
82 [ $id != 256 ] && exit 1
83
84 echo "Testing data clear..."
85 $ecli cl-data $DEVICE:/soundbanks/H/256
86 [ $? -ne 0 ] && exit 1
87
88 exit 0
+0
-123
test/full_test.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 sleep 1
10
11 echo "Testing info..."
12 $ecli info $DEVICE:/
13 [ $? -ne 0 ] && exit 1
14
15 sleep 1
16
17 echo "Testing df..."
18 $ecli df $DEVICE:/
19 [ $? -ne 0 ] && exit 1
20
21 sleep 1
22
23 echo "Testing ls..."
24 $ecli ls $DEVICE:/
25 [ $? -ne 0 ] && exit 1
26
27 sleep 1
28
29 echo "Testing mkdir..."
30 $ecli mkdir $DEVICE:/$TEST_NAME
31 [ $? -ne 0 ] && exit 1
32
33 sleep 1
34
35 $ecli ls $DEVICE:/$TEST_NAME
36 [ $? -ne 0 ] && exit 1
37
38 sleep 1
39
40 echo "Testing upload..."
41 $ecli upload $srcdir/res/square.wav $DEVICE:/$TEST_NAME
42 [ $? -ne 0 ] && exit 1
43
44 sleep 1
45
46 output=$($ecli ls $DEVICE:/$TEST_NAME)
47 echo $output
48 type=$(echo $output | awk '{print $1}')
49 size=$(echo $output | awk '{print $2}')
50 name=$(echo $output | awk '{print $4}')
51 [ "$type" != "F" ] || [ "$size" != "0.09" ] || [ "$name" != "square" ] && exit 1
52
53 sleep 1
54
55 echo "Testing upload (nonexistent source)..."
56 $ecli upload $srcdir/res/foo $DEVICE:/$TEST_NAME
57 [ $? -eq 0 ] && exit 1
58
59 sleep 1
60
61 echo "Testing download..."
62 $ecli download $DEVICE:/$TEST_NAME/square
63 [ $? -ne 0 ] && exit 1
64 actual_cksum="$(cksum square.wav | awk '{print $1}')"
65 rm square.wav
66 [ "$actual_cksum" != "$(cksum $srcdir/res/square.wav | awk '{print $1}')" ] && exit 1
67
68 sleep 1
69
70 echo "Testing download (nonexistent source)..."
71 $ecli download $DEVICE:/$TEST_NAME/foo
72 [ $? -eq 0 ] && exit 1
73
74 sleep 1
75
76 echo "Testing mv..."
77 $ecli mv $DEVICE:/$TEST_NAME/square $DEVICE:/$TEST_NAME/sample
78 [ $? -ne 0 ] && exit 1
79
80 sleep 1
81
82 echo "Testing mv..."
83 $ecli mv $DEVICE:/$TEST_NAME/foo $DEVICE:/$TEST_NAME/sample
84 [ $? -eq 0 ] && exit 1
85
86 sleep 1
87
88 echo "Testing rm..."
89 $ecli rm $DEVICE:/$TEST_NAME/sample
90 [ $? -ne 0 ] && exit 1
91
92 sleep 1
93
94 echo "Testing rm (nonexistent file)..."
95 $ecli rm $DEVICE:/$TEST_NAME/sample
96 [ $? -eq 0 ] && exit 1
97
98 sleep 1
99
100 echo "Testing rmdir..."
101 $ecli rmdir $DEVICE:/$TEST_NAME
102 [ $? -ne 0 ] && exit 1
103
104 sleep 1
105
106 echo "Testing rmdir (nonexistent dir)..."
107 $ecli rmdir $DEVICE:/$TEST_NAME
108 [ $? -eq 0 ] && exit 1
109
110 sleep 1
111
112 echo "Testing ls (nonexistent dir)..."
113 $ecli ls $DEVICE:/$TEST_NAME
114 [ $? -eq 0 ] && exit 1
115
116 sleep 1
117
118 echo "Testing ls (nonexistent dir inside nonexistent dir)..."
119 $ecli ls $DEVICE:/$TEST_NAME/foo
120 [ $? -eq 0 ] && exit 1
121
122 exit 0
Binary diff not shown
Binary diff not shown
Binary diff not shown
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 | awk '{print $1}')
39 size=$(echo $output | awk '{print $2}')
40 name=$(echo $output | 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