New upstream version 2.0
Dennis Braun
2 years ago
0 | 0 | ACLOCAL_AMFLAGS=-I m4 |
1 | ||
2 | if CLI_ONLY | |
3 | SUBDIRS=src test man | |
4 | else | |
1 | 5 | SUBDIRS=src res test po man |
6 | endif |
0 | 0 | # Elektroid |
1 | 1 | |
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. | |
4 | 6 | |
5 | 7 | ## Installation |
6 | 8 | |
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`. | |
8 | 10 | |
9 | 11 | ``` |
10 | 12 | autoreconf --install |
15 | 17 | |
16 | 18 | The package dependencies for Debian based distributions are: |
17 | 19 | - automake |
20 | - libtool | |
21 | - build-essential | |
18 | 22 | - libasound2-dev |
19 | 23 | - libgtk-3-dev |
20 | 24 | - libpulse-dev |
21 | 25 | - libsndfile1-dev |
22 | 26 | - libsamplerate0-dev |
23 | - libtool | |
24 | 27 | - autopoint |
25 | 28 | - gettext |
26 | 29 | - 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`. | |
29 | 36 | |
30 | 37 | ## CLI |
31 | 38 | |
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 | |
36 | 73 | |
37 | 74 | ``` |
38 | 75 | $ elektroid-cli ld |
39 | 76 | 0 Elektron Digitakt MIDI 1 |
40 | 77 | ``` |
41 | 78 | |
42 | * info, show device info | |
79 | * `info` or `info-device`, show device info including device filesystems | |
43 | 80 | |
44 | 81 | ``` |
45 | 82 | $ 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 | |
50 | 87 | |
51 | 88 | ``` |
52 | 89 | $ 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 | ``` |
1 | 1 | # Process this file with autoconf to produce a configure script. |
2 | 2 | |
3 | 3 | AC_PREREQ([2.69]) |
4 | AC_INIT([elektroid],[1.4],[dagargo@gmail.com]) | |
4 | AC_INIT([elektroid],[2.0],[dagargo@gmail.com]) | |
5 | 5 | AC_CONFIG_SRCDIR([src]) |
6 | 6 | AC_CONFIG_HEADERS([config.h]) |
7 | 7 | AM_PROG_LIBTOOL |
12 | 12 | # Checks for programs. |
13 | 13 | AC_PROG_CC |
14 | 14 | |
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 | ||
15 | 19 | # 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])]) | |
18 | 24 | |
19 | 25 | PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.2, ac_cv_sndfile=1, ac_cv_sndfile=0) |
20 | 26 | AC_DEFINE_UNQUOTED([HAVE_SNDFILE],${ac_cv_sndfile}, [Set to 1 if you have libsndfile.]) |
21 | 27 | AC_SUBST(SNDFILE_CFLAGS) |
22 | 28 | AC_SUBST(SNDFILE_LIBS) |
23 | 29 | |
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) | |
25 | 31 | AC_DEFINE_UNQUOTED([HAVE_SAMPLERATE],${ac_cv_samplerate}, [Set to 1 if you have libsamplerate.]) |
26 | 32 | AC_SUBST(SAMPLERATE_CFLAGS) |
27 | 33 | AC_SUBST(SAMPLERATE_LIBS) |
28 | 34 | |
29 | PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 5.0]) | |
35 | AM_COND_IF(GUI, [PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 5.0])]) | |
30 | 36 | AC_SUBST(PULSEAUDIO_CFLAGS) |
31 | 37 | AC_SUBST(PULSEAUDIO_LIBS) |
32 | 38 | |
39 | AM_COND_IF(GUI, [ | |
33 | 40 | AM_GNU_GETTEXT([external]) |
34 | AM_GNU_GETTEXT_VERSION([0.19.8]) | |
41 | AM_GNU_GETTEXT_VERSION([0.12.1]) | |
42 | ]) | |
35 | 43 | |
36 | 44 | # Checks for header files. |
37 | AC_CHECK_HEADERS([unistd.h limits.h zlib.h]) | |
45 | AC_CHECK_HEADERS([unistd.h limits.h]) | |
38 | 46 | |
39 | 47 | # Checks for typedefs, structures, and compiler characteristics. |
40 | 48 |
0 | if CLI_ONLY | |
1 | dist_man1_MANS = elektroid-cli.1 | |
2 | else | |
0 | 3 | 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 | ||
1 | 2 | .SH NAME |
2 | elektroid-cli \- sample transfer CLI application for Elektron devices | |
3 | elektroid-cli \- transfer CLI application for Elektron devices | |
4 | ||
3 | 5 | .SH SYNOPSIS |
4 | 6 | .B elektroid-cli |
5 | 7 | .RI [ options ] |
6 | 8 | .RI command |
9 | ||
7 | 10 | .SH DESCRIPTION |
8 | 11 | .B elektroid-cli |
9 | 12 | provides the same funcionality than elektroid. See man elektroid for the GUI application. |
10 | 13 | .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 | |
13 | 17 | .TP |
14 | .B ld | |
18 | [ \fBld\fR | \fBlist-devices\fR ] | |
15 | 19 | List compatible devices |
16 | 20 | .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 | |
18 | 25 | Show device info |
19 | 26 | .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 | |
21 | 35 | List directory contents |
22 | 36 | .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 | |
25 | 39 | .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 | |
28 | 42 | .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. | |
31 | 45 | .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. | |
34 | 48 | .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. | |
37 | 51 | .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 | ||
40 | 64 | .SH OPTIONS |
41 | 65 | .TP |
42 | 66 | \fB\-v\fR |
43 | 67 | Show verbose output. Use it more than once for more verbosity. |
44 | 68 | .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 | ||
45 | 84 | .SH "SEE ALSO" |
46 | 85 | The GitHub page provides some examples: <https://github.com/dagargo/elektroid> |
86 | ||
47 | 87 | .SH "AUTHOR" |
48 | 88 | elektroid-cli was written by David García Goñi <dagargo@gmail.com>. |
49 | 89 | .PP |
0 | .TH ELEKTROID "1" "Feb 2020" | |
0 | .TH ELEKTROID "1" "Dec 2021" | |
1 | ||
1 | 2 | .SH NAME |
2 | elektroid \- sample transfer application for Elektron devices | |
3 | elektroid \- transfer application for Elektron devices | |
4 | ||
3 | 5 | .SH SYNOPSIS |
4 | 6 | .B elektroid |
5 | 7 | .RI [ options ] |
8 | ||
6 | 9 | .SH DESCRIPTION |
7 | 10 | .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. | |
9 | 12 | .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. | |
11 | 14 | .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 | ||
13 | 17 | .SH OPTIONS |
14 | 18 | .TP |
15 | \fB\-l\fR <local directory> | |
19 | \fB\-l\fR, \fB--local-directory\fR <local directory> | |
16 | 20 | Open the provided local directory |
17 | 21 | .TP |
18 | \fB\-v\fR | |
22 | \fB\-v\fR, \fB--verbose\fR | |
19 | 23 | 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 | |
20 | 27 | .PP |
28 | ||
21 | 29 | .SH "AUTHOR" |
22 | 30 | elektroid was written by David García Goñi <dagargo@gmail.com>. |
31 | ||
23 | 32 | .PP |
24 | 33 | This manual page was written by Dennis Braun <d_braun@kabelmail.de> |
25 | 34 | for the Debian project (but may be used by others). |
6 | 6 | msgstr "" |
7 | 7 | "Project-Id-Version: elektroid 1.4\n" |
8 | 8 | "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" | |
10 | 10 | "PO-Revision-Date: 2020-04-26 13:00+0100\n" |
11 | 11 | "Last-Translator: David García Goñi <dagargo@gmail.com>\n" |
12 | 12 | "Language-Team: Catalan\n" |
16 | 16 | "Content-Transfer-Encoding: 8bit\n" |
17 | 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" |
18 | 18 | |
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 | |
20 | 40 | #, c-format |
21 | 41 | msgid "Connected to %s%s" |
22 | 42 | msgstr "Connectat a %s%s" |
23 | 43 | |
24 | #: src/elektroid.c:283 src/elektroid.c:3172 | |
44 | #: src/elektroid.c:406 src/elektroid.c:3215 | |
25 | 45 | msgid "Not connected" |
26 | 46 | msgstr "No connectat" |
27 | 47 | |
28 | #: src/elektroid.c:424 | |
48 | #: src/elektroid.c:549 | |
29 | 49 | msgid "Waiting..." |
30 | 50 | msgstr "Esperant..." |
31 | 51 | |
32 | #: src/elektroid.c:427 | |
52 | #: src/elektroid.c:552 | |
33 | 53 | msgid "Sending..." |
34 | 54 | msgstr "Enviant..." |
35 | 55 | |
36 | #: src/elektroid.c:431 | |
56 | #: src/elektroid.c:556 | |
37 | 57 | msgid "Receiving..." |
38 | 58 | msgstr "Rebent..." |
39 | 59 | |
40 | #: src/elektroid.c:499 | |
60 | #: src/elektroid.c:624 | |
41 | 61 | msgid "Receive SysEx" |
42 | 62 | msgstr "Rep SysEx" |
43 | 63 | |
44 | #: src/elektroid.c:521 | |
64 | #: src/elektroid.c:648 | |
45 | 65 | msgid "Save SysEx" |
46 | 66 | msgstr "Alça SysEx" |
47 | 67 | |
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 | |
49 | 69 | msgid "_Cancel" |
50 | 70 | msgstr "_Cancel·la" |
51 | 71 | |
52 | #: src/elektroid.c:526 | |
72 | #: src/elektroid.c:653 | |
53 | 73 | msgid "_Save" |
54 | 74 | msgstr "_Alça" |
55 | 75 | |
56 | #: src/elektroid.c:530 | |
76 | #: src/elektroid.c:657 | |
57 | 77 | msgid "Received SysEx" |
58 | 78 | msgstr "SysEx rebut" |
59 | 79 | |
60 | #: src/elektroid.c:535 src/elektroid.c:635 | |
80 | #: src/elektroid.c:662 src/elektroid.c:753 | |
61 | 81 | msgid "SysEx Files" |
62 | 82 | msgstr "Fitxers SysEx" |
63 | 83 | |
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 | |
65 | 90 | msgid "Open SysEx" |
66 | 91 | msgstr "Obri SysEx" |
67 | 92 | |
68 | #: src/elektroid.c:631 | |
93 | #: src/elektroid.c:749 | |
69 | 94 | msgid "_Open" |
70 | 95 | msgstr "_Obri" |
71 | 96 | |
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 | |
73 | 103 | msgid "Send SysEx" |
74 | 104 | msgstr "Envia SysEx" |
75 | 105 | |
76 | #: src/elektroid.c:779 | |
106 | #: src/elektroid.c:882 | |
77 | 107 | #, c-format |
78 | 108 | msgid "Error while deleting “%s”: %s." |
79 | 109 | msgstr "Error al eliminar «%s»: %s." |
80 | 110 | |
81 | #: src/elektroid.c:811 | |
111 | #: src/elektroid.c:914 | |
82 | 112 | msgid "Are you sure you want to delete the selected items?" |
83 | 113 | msgstr "Està segur de que vol eliminar els elements seleccionats?" |
84 | 114 | |
85 | #: src/elektroid.c:813 | |
115 | #: src/elektroid.c:916 | |
86 | 116 | msgid "_Delete" |
87 | 117 | msgstr "_Elimina" |
88 | 118 | |
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 | |
90 | 120 | msgid "Rename" |
91 | 121 | msgstr "Canvia el nom" |
92 | 122 | |
93 | #: src/elektroid.c:885 | |
123 | #: src/elektroid.c:987 | |
94 | 124 | #, c-format |
95 | 125 | msgid "Error while renaming to “%s”: %s." |
96 | 126 | msgstr "Error al canviar el nom a «%s»: %s." |
97 | 127 | |
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 | |
99 | 129 | msgid "Add Directory" |
100 | 130 | msgstr "Afig directori" |
101 | 131 | |
102 | #: src/elektroid.c:1635 | |
132 | #: src/elektroid.c:1568 | |
103 | 133 | #, c-format |
104 | 134 | msgid "Error while creating dir “%s”: %s." |
105 | 135 | msgstr "Error al crear el directori «%s»: %s." |
106 | 136 | |
107 | #: src/elektroid.c:1797 | |
137 | #: src/elektroid.c:1640 | |
108 | 138 | msgid "Queued" |
109 | 139 | msgstr "A la cua" |
110 | 140 | |
111 | #: src/elektroid.c:1799 | |
141 | #: src/elektroid.c:1642 | |
112 | 142 | msgid "Running" |
113 | 143 | msgstr "Executant" |
114 | 144 | |
115 | #: src/elektroid.c:1801 | |
145 | #: src/elektroid.c:1644 | |
116 | 146 | msgid "Completed" |
117 | 147 | msgstr "Completada" |
118 | 148 | |
119 | #: src/elektroid.c:1803 | |
149 | #: src/elektroid.c:1646 | |
120 | 150 | msgid "Completed with errors" |
121 | 151 | msgstr "Completada amb errors" |
122 | 152 | |
123 | #: src/elektroid.c:1805 | |
153 | #: src/elektroid.c:1648 | |
124 | 154 | msgid "Canceled" |
125 | 155 | msgstr "Cancel·lada" |
126 | 156 | |
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 | |
132 | 158 | msgid "Upload" |
133 | 159 | msgstr "Càrrega" |
134 | 160 | |
135 | #: src/elektroid.c:1819 | |
161 | #: src/elektroid.c:1662 | |
136 | 162 | msgid "Download" |
137 | 163 | msgstr "Descàrrega" |
138 | 164 | |
139 | #: src/elektroid.c:2613 src/elektroid.c:2643 | |
165 | #: src/elektroid.c:2518 src/elektroid.c:2559 | |
140 | 166 | #, c-format |
141 | 167 | msgid "Error while moving from “%s” to “%s”: %s." |
142 | 168 | msgstr "Error al moure de «%s» a «%s»: %s." |
143 | 169 | |
144 | #: res/gui.glade:55 | |
170 | #: res/gui.glade:70 | |
145 | 171 | msgid "Upload Selection" |
146 | 172 | msgstr "Carrega la selecció" |
147 | 173 | |
148 | #: res/gui.glade:70 | |
174 | #: res/gui.glade:85 | |
149 | 175 | msgid "Play" |
150 | 176 | msgstr "Reproduïx" |
151 | 177 | |
152 | #: res/gui.glade:84 | |
178 | #: res/gui.glade:99 | |
153 | 179 | msgid "Open With External Editor" |
154 | 180 | msgstr "Obri amb l'editor extern" |
155 | 181 | |
156 | #: res/gui.glade:92 | |
182 | #: res/gui.glade:107 | |
157 | 183 | msgid "Show in File Manager" |
158 | 184 | msgstr "Mostra al navegador de fitxers" |
159 | 185 | |
160 | #: res/gui.glade:115 res/gui.glade:164 | |
186 | #: res/gui.glade:139 res/gui.glade:202 | |
161 | 187 | msgid "Delete" |
162 | 188 | msgstr "Elimina" |
163 | 189 | |
164 | #: res/gui.glade:140 | |
190 | #: res/gui.glade:168 | |
165 | 191 | msgid "Download Selection" |
166 | 192 | msgstr "Descarrega la selecció" |
167 | 193 | |
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 | |
174 | 199 | msgid "translator-credits" |
175 | 200 | msgstr "David García Goñi <dagargo@gmail.com>" |
176 | 201 | |
177 | #: res/gui.glade:250 | |
202 | #: res/gui.glade:289 | |
178 | 203 | msgid "_Receive SysEx" |
179 | 204 | msgstr "_Rep SysEx" |
180 | 205 | |
181 | #: res/gui.glade:263 | |
206 | #: res/gui.glade:302 | |
182 | 207 | msgid "_Send SysEx" |
183 | 208 | msgstr "_Envia SysEx" |
184 | 209 | |
185 | #: res/gui.glade:287 | |
210 | #: res/gui.glade:326 | |
186 | 211 | msgid "OS _Upgrade" |
187 | 212 | msgstr "_Actualitza el SO" |
188 | 213 | |
189 | #: res/gui.glade:311 | |
214 | #: res/gui.glade:350 | |
190 | 215 | msgid "_About" |
191 | 216 | msgstr "_Quant a" |
192 | 217 | |
193 | #: res/gui.glade:424 res/gui.glade:607 | |
218 | #: res/gui.glade:434 res/gui.glade:583 | |
194 | 219 | msgid "Go to Parent Directory" |
195 | 220 | msgstr "Ves al directori pare" |
196 | 221 | |
197 | #: res/gui.glade:466 res/gui.glade:649 | |
222 | #: res/gui.glade:455 res/gui.glade:604 | |
198 | 223 | msgid "Refresh Directory" |
199 | 224 | msgstr "Actualitza el directori" |
200 | 225 | |
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 | |
202 | 227 | msgid "Name" |
203 | 228 | msgstr "Nom" |
204 | 229 | |
205 | #: res/gui.glade:544 res/gui.glade:727 | |
230 | #: res/gui.glade:526 res/gui.glade:685 | |
206 | 231 | msgid "Size" |
207 | 232 | msgstr "Mida" |
208 | 233 | |
209 | #: res/gui.glade:780 | |
234 | #: res/gui.glade:738 | |
210 | 235 | msgid "Refresh Devices" |
211 | 236 | msgstr "Actualitza els dispositius" |
212 | 237 | |
213 | 238 | #. 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 | |
215 | 240 | msgid "Auto play" |
216 | 241 | msgstr "" |
217 | 242 | "Reproducció\n" |
218 | 243 | "automàtica" |
219 | 244 | |
220 | #: res/gui.glade:1092 | |
245 | #: res/gui.glade:1088 | |
221 | 246 | msgid "Status" |
222 | 247 | msgstr "Estat" |
223 | 248 | |
224 | #: res/gui.glade:1103 | |
249 | #: res/gui.glade:1099 | |
225 | 250 | msgid "Type" |
226 | 251 | msgstr "Tipus" |
227 | 252 | |
228 | #: res/gui.glade:1114 | |
253 | #: res/gui.glade:1120 | |
229 | 254 | msgid "Source" |
230 | 255 | msgstr "Origen" |
231 | 256 | |
232 | #: res/gui.glade:1128 | |
257 | #: res/gui.glade:1134 | |
233 | 258 | msgid "Destination" |
234 | 259 | msgstr "Destinació" |
235 | 260 | |
236 | #: res/gui.glade:1143 | |
261 | #: res/gui.glade:1149 | |
237 | 262 | msgid "Progress" |
238 | 263 | msgstr "Progrés" |
239 | 264 | |
240 | #: res/gui.glade:1175 | |
265 | #: res/gui.glade:1181 | |
241 | 266 | msgid "Cancel Tasks" |
242 | 267 | msgstr "Cancel·la les tasques" |
243 | 268 | |
244 | #: res/gui.glade:1196 | |
269 | #: res/gui.glade:1202 | |
245 | 270 | msgid "Remove Queued Tasks" |
246 | 271 | msgstr "Elimina les tasques de la cua" |
247 | 272 | |
248 | #: res/gui.glade:1217 | |
273 | #: res/gui.glade:1223 | |
249 | 274 | msgid "Clear Finished Tasks" |
250 | 275 | msgstr "Neteja les tasques terminadas" |
6 | 6 | msgstr "" |
7 | 7 | "Project-Id-Version: elektroid 1.4\n" |
8 | 8 | "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" | |
10 | 10 | "PO-Revision-Date: 2021-01-11 22:00+0100\n" |
11 | 11 | "Last-Translator: Dennis Braun <d_braun@kabelmail.de>\n" |
12 | 12 | "Language-Team: German\n" |
16 | 16 | "Content-Transfer-Encoding: 8bit\n" |
17 | 17 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" |
18 | 18 | |
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 | |
20 | 40 | #, c-format |
21 | 41 | msgid "Connected to %s%s" |
22 | 42 | msgstr "Verbunden mit %s%s" |
23 | 43 | |
24 | #: src/elektroid.c:283 src/elektroid.c:3172 | |
44 | #: src/elektroid.c:406 src/elektroid.c:3215 | |
25 | 45 | msgid "Not connected" |
26 | 46 | msgstr "Nicht verbunden" |
27 | 47 | |
28 | #: src/elektroid.c:424 | |
48 | #: src/elektroid.c:549 | |
29 | 49 | msgid "Waiting..." |
30 | 50 | msgstr "Warte..." |
31 | 51 | |
32 | #: src/elektroid.c:427 | |
52 | #: src/elektroid.c:552 | |
33 | 53 | msgid "Sending..." |
34 | 54 | msgstr "Sende..." |
35 | 55 | |
36 | #: src/elektroid.c:431 | |
56 | #: src/elektroid.c:556 | |
37 | 57 | msgid "Receiving..." |
38 | 58 | msgstr "Empfange..." |
39 | 59 | |
40 | #: src/elektroid.c:499 | |
60 | #: src/elektroid.c:624 | |
41 | 61 | msgid "Receive SysEx" |
42 | 62 | msgstr "Empfange SysEx" |
43 | 63 | |
44 | #: src/elektroid.c:521 | |
64 | #: src/elektroid.c:648 | |
45 | 65 | msgid "Save SysEx" |
46 | 66 | msgstr "Speichere SysEx" |
47 | 67 | |
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 | |
49 | 69 | msgid "_Cancel" |
50 | 70 | msgstr "_Abbrechen" |
51 | 71 | |
52 | #: src/elektroid.c:526 | |
72 | #: src/elektroid.c:653 | |
53 | 73 | msgid "_Save" |
54 | 74 | msgstr "_Speichern" |
55 | 75 | |
56 | #: src/elektroid.c:530 | |
76 | #: src/elektroid.c:657 | |
57 | 77 | msgid "Received SysEx" |
58 | 78 | msgstr "SysEx empfangen" |
59 | 79 | |
60 | #: src/elektroid.c:535 src/elektroid.c:635 | |
80 | #: src/elektroid.c:662 src/elektroid.c:753 | |
61 | 81 | msgid "SysEx Files" |
62 | 82 | msgstr "SysEx Dateien" |
63 | 83 | |
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 | |
65 | 90 | msgid "Open SysEx" |
66 | 91 | msgstr "Öffne SysEx" |
67 | 92 | |
68 | #: src/elektroid.c:631 | |
93 | #: src/elektroid.c:749 | |
69 | 94 | msgid "_Open" |
70 | 95 | msgstr "_Öffnen" |
71 | 96 | |
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 | |
73 | 103 | msgid "Send SysEx" |
74 | 104 | msgstr "Sende SysEx" |
75 | 105 | |
76 | #: src/elektroid.c:779 | |
106 | #: src/elektroid.c:882 | |
77 | 107 | #, c-format |
78 | 108 | msgid "Error while deleting “%s”: %s." |
79 | 109 | msgstr "Fehler beim Löschen »%s«: %s." |
80 | 110 | |
81 | #: src/elektroid.c:811 | |
111 | #: src/elektroid.c:914 | |
82 | 112 | msgid "Are you sure you want to delete the selected items?" |
83 | 113 | msgstr "Bist du sicher das du die ausgewählten Elemente löschen möchtest?" |
84 | 114 | |
85 | #: src/elektroid.c:813 | |
115 | #: src/elektroid.c:916 | |
86 | 116 | msgid "_Delete" |
87 | 117 | msgstr "_Löschen" |
88 | 118 | |
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 | |
90 | 120 | msgid "Rename" |
91 | 121 | msgstr "Umbenennen" |
92 | 122 | |
93 | #: src/elektroid.c:885 | |
123 | #: src/elektroid.c:987 | |
94 | 124 | #, c-format |
95 | 125 | msgid "Error while renaming to “%s”: %s." |
96 | 126 | msgstr "Fehler beim Umbenennen von »%s«: %s." |
97 | 127 | |
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 | |
99 | 129 | msgid "Add Directory" |
100 | 130 | msgstr "Verzeichnis hinzufügen" |
101 | 131 | |
102 | #: src/elektroid.c:1635 | |
132 | #: src/elektroid.c:1568 | |
103 | 133 | #, c-format |
104 | 134 | msgid "Error while creating dir “%s”: %s." |
105 | 135 | msgstr "Fehler beim Erstellen des Verzeichnisses »%s«: %s." |
106 | 136 | |
107 | #: src/elektroid.c:1797 | |
137 | #: src/elektroid.c:1640 | |
108 | 138 | msgid "Queued" |
109 | 139 | msgstr "In der Warteschlange" |
110 | 140 | |
111 | #: src/elektroid.c:1799 | |
141 | #: src/elektroid.c:1642 | |
112 | 142 | msgid "Running" |
113 | 143 | msgstr "Wird ausgeführt" |
114 | 144 | |
115 | #: src/elektroid.c:1801 | |
145 | #: src/elektroid.c:1644 | |
116 | 146 | msgid "Completed" |
117 | 147 | msgstr "Fertig" |
118 | 148 | |
119 | #: src/elektroid.c:1803 | |
149 | #: src/elektroid.c:1646 | |
120 | 150 | msgid "Completed with errors" |
121 | 151 | msgstr "Abgeschlossen mit Fehlern" |
122 | 152 | |
123 | #: src/elektroid.c:1805 | |
153 | #: src/elektroid.c:1648 | |
124 | 154 | msgid "Canceled" |
125 | 155 | msgstr "Abgebrochen" |
126 | 156 | |
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 | |
132 | 158 | msgid "Upload" |
133 | 159 | msgstr "Hochladen" |
134 | 160 | |
135 | #: src/elektroid.c:1819 | |
161 | #: src/elektroid.c:1662 | |
136 | 162 | msgid "Download" |
137 | 163 | msgstr "Herunterladen" |
138 | 164 | |
139 | #: src/elektroid.c:2613 src/elektroid.c:2643 | |
165 | #: src/elektroid.c:2518 src/elektroid.c:2559 | |
140 | 166 | #, c-format |
141 | 167 | msgid "Error while moving from “%s” to “%s”: %s." |
142 | 168 | msgstr "Fehler beim Verschieben von »%s« nach »%s«: %s." |
143 | 169 | |
144 | #: res/gui.glade:55 | |
170 | #: res/gui.glade:70 | |
145 | 171 | msgid "Upload Selection" |
146 | 172 | msgstr "Upload Auswahl" |
147 | 173 | |
148 | #: res/gui.glade:70 | |
174 | #: res/gui.glade:85 | |
149 | 175 | msgid "Play" |
150 | 176 | msgstr "Abspielen" |
151 | 177 | |
152 | #: res/gui.glade:84 | |
178 | #: res/gui.glade:99 | |
153 | 179 | msgid "Open With External Editor" |
154 | 180 | msgstr "Öffnen mit externen Editor" |
155 | 181 | |
156 | #: res/gui.glade:92 | |
182 | #: res/gui.glade:107 | |
157 | 183 | msgid "Show in File Manager" |
158 | 184 | msgstr "Im Dateimanager _Anzeigen" |
159 | 185 | |
160 | #: res/gui.glade:115 res/gui.glade:164 | |
186 | #: res/gui.glade:139 res/gui.glade:202 | |
161 | 187 | msgid "Delete" |
162 | 188 | msgstr "Löschen" |
163 | 189 | |
164 | #: res/gui.glade:140 | |
190 | #: res/gui.glade:168 | |
165 | 191 | msgid "Download Selection" |
166 | 192 | msgstr "Download Auswahl" |
167 | 193 | |
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 | |
173 | 200 | msgid "translator-credits" |
174 | 201 | msgstr "Dennis Braun <d_braun@kabelmail.de>" |
175 | 202 | |
176 | #: res/gui.glade:250 | |
203 | #: res/gui.glade:289 | |
177 | 204 | msgid "_Receive SysEx" |
178 | 205 | msgstr "_Empfange SysEx" |
179 | 206 | |
180 | #: res/gui.glade:263 | |
207 | #: res/gui.glade:302 | |
181 | 208 | msgid "_Send SysEx" |
182 | 209 | msgstr "_Sende SysEx" |
183 | 210 | |
184 | #: res/gui.glade:287 | |
211 | #: res/gui.glade:326 | |
185 | 212 | msgid "OS _Upgrade" |
186 | 213 | msgstr "OS _Aktualisierung" |
187 | 214 | |
188 | #: res/gui.glade:311 | |
215 | #: res/gui.glade:350 | |
189 | 216 | msgid "_About" |
190 | 217 | msgstr "_Info" |
191 | 218 | |
192 | #: res/gui.glade:424 res/gui.glade:607 | |
219 | #: res/gui.glade:434 res/gui.glade:583 | |
193 | 220 | msgid "Go to Parent Directory" |
194 | 221 | msgstr "Gehe zum Überverzeichnis" |
195 | 222 | |
196 | #: res/gui.glade:466 res/gui.glade:649 | |
223 | #: res/gui.glade:455 res/gui.glade:604 | |
197 | 224 | msgid "Refresh Directory" |
198 | 225 | msgstr "Aktualisiere Verzeichnis" |
199 | 226 | |
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 | |
201 | 228 | msgid "Name" |
202 | 229 | msgstr "Name" |
203 | 230 | |
204 | #: res/gui.glade:544 res/gui.glade:727 | |
231 | #: res/gui.glade:526 res/gui.glade:685 | |
205 | 232 | msgid "Size" |
206 | 233 | msgstr "Größe" |
207 | 234 | |
208 | #: res/gui.glade:780 | |
235 | #: res/gui.glade:738 | |
209 | 236 | msgid "Refresh Devices" |
210 | 237 | msgstr "Aktualisiere Geräte" |
211 | 238 | |
212 | 239 | #. 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 | |
214 | 241 | msgid "Auto play" |
215 | 242 | msgstr "Auto Play" |
216 | 243 | |
217 | #: res/gui.glade:1092 | |
244 | #: res/gui.glade:1088 | |
218 | 245 | msgid "Status" |
219 | 246 | msgstr "Status" |
220 | 247 | |
221 | #: res/gui.glade:1103 | |
248 | #: res/gui.glade:1099 | |
222 | 249 | msgid "Type" |
223 | 250 | msgstr "Typ" |
224 | 251 | |
225 | #: res/gui.glade:1114 | |
252 | #: res/gui.glade:1120 | |
226 | 253 | msgid "Source" |
227 | 254 | msgstr "Quelle" |
228 | 255 | |
229 | #: res/gui.glade:1128 | |
256 | #: res/gui.glade:1134 | |
230 | 257 | msgid "Destination" |
231 | 258 | msgstr "Ziel" |
232 | 259 | |
233 | #: res/gui.glade:1143 | |
260 | #: res/gui.glade:1149 | |
234 | 261 | msgid "Progress" |
235 | 262 | msgstr "Fortschritt" |
236 | 263 | |
237 | #: res/gui.glade:1175 | |
264 | #: res/gui.glade:1181 | |
238 | 265 | msgid "Cancel Tasks" |
239 | 266 | msgstr "Aufgaben abbrechen" |
240 | 267 | |
241 | #: res/gui.glade:1196 | |
268 | #: res/gui.glade:1202 | |
242 | 269 | msgid "Remove Queued Tasks" |
243 | 270 | msgstr "Lösche Aufgaben in der Warteschlange" |
244 | 271 | |
245 | #: res/gui.glade:1217 | |
272 | #: res/gui.glade:1223 | |
246 | 273 | msgid "Clear Finished Tasks" |
247 | 274 | msgstr "Abgeschlossene Aufgaben aufräumen" |
5 | 5 | #, fuzzy |
6 | 6 | msgid "" |
7 | 7 | msgstr "" |
8 | "Project-Id-Version: elektroid 1.4\n" | |
8 | "Project-Id-Version: elektroid 2.0-beta\n" | |
9 | 9 | "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" | |
11 | 11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
12 | 12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
13 | 13 | "Language-Team: LANGUAGE <LL@li.org>\n" |
16 | 16 | "Content-Type: text/plain; charset=UTF-8\n" |
17 | 17 | "Content-Transfer-Encoding: 8bit\n" |
18 | 18 | |
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 | |
20 | 40 | #, c-format |
21 | 41 | msgid "Connected to %s%s" |
22 | 42 | msgstr "" |
23 | 43 | |
24 | #: src/elektroid.c:283 src/elektroid.c:3172 | |
44 | #: src/elektroid.c:406 src/elektroid.c:3215 | |
25 | 45 | msgid "Not connected" |
26 | 46 | msgstr "" |
27 | 47 | |
28 | #: src/elektroid.c:424 | |
48 | #: src/elektroid.c:549 | |
29 | 49 | msgid "Waiting..." |
30 | 50 | msgstr "" |
31 | 51 | |
32 | #: src/elektroid.c:427 | |
52 | #: src/elektroid.c:552 | |
33 | 53 | msgid "Sending..." |
34 | 54 | msgstr "" |
35 | 55 | |
36 | #: src/elektroid.c:431 | |
56 | #: src/elektroid.c:556 | |
37 | 57 | msgid "Receiving..." |
38 | 58 | msgstr "" |
39 | 59 | |
40 | #: src/elektroid.c:499 | |
60 | #: src/elektroid.c:624 | |
41 | 61 | msgid "Receive SysEx" |
42 | 62 | msgstr "" |
43 | 63 | |
44 | #: src/elektroid.c:521 | |
64 | #: src/elektroid.c:648 | |
45 | 65 | msgid "Save SysEx" |
46 | 66 | msgstr "" |
47 | 67 | |
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 | |
49 | 69 | msgid "_Cancel" |
50 | 70 | msgstr "" |
51 | 71 | |
52 | #: src/elektroid.c:526 | |
72 | #: src/elektroid.c:653 | |
53 | 73 | msgid "_Save" |
54 | 74 | msgstr "" |
55 | 75 | |
56 | #: src/elektroid.c:530 | |
76 | #: src/elektroid.c:657 | |
57 | 77 | msgid "Received SysEx" |
58 | 78 | msgstr "" |
59 | 79 | |
60 | #: src/elektroid.c:535 src/elektroid.c:635 | |
80 | #: src/elektroid.c:662 src/elektroid.c:753 | |
61 | 81 | msgid "SysEx Files" |
62 | 82 | msgstr "" |
63 | 83 | |
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 | |
65 | 90 | msgid "Open SysEx" |
66 | 91 | msgstr "" |
67 | 92 | |
68 | #: src/elektroid.c:631 | |
93 | #: src/elektroid.c:749 | |
69 | 94 | msgid "_Open" |
70 | 95 | msgstr "" |
71 | 96 | |
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 | |
73 | 103 | msgid "Send SysEx" |
74 | 104 | msgstr "" |
75 | 105 | |
76 | #: src/elektroid.c:779 | |
106 | #: src/elektroid.c:882 | |
77 | 107 | #, c-format |
78 | 108 | msgid "Error while deleting “%s”: %s." |
79 | 109 | msgstr "" |
80 | 110 | |
81 | #: src/elektroid.c:811 | |
111 | #: src/elektroid.c:914 | |
82 | 112 | msgid "Are you sure you want to delete the selected items?" |
83 | 113 | msgstr "" |
84 | 114 | |
85 | #: src/elektroid.c:813 | |
115 | #: src/elektroid.c:916 | |
86 | 116 | msgid "_Delete" |
87 | 117 | msgstr "" |
88 | 118 | |
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 | |
90 | 120 | msgid "Rename" |
91 | 121 | msgstr "" |
92 | 122 | |
93 | #: src/elektroid.c:885 | |
123 | #: src/elektroid.c:987 | |
94 | 124 | #, c-format |
95 | 125 | msgid "Error while renaming to “%s”: %s." |
96 | 126 | msgstr "" |
97 | 127 | |
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 | |
99 | 129 | msgid "Add Directory" |
100 | 130 | msgstr "" |
101 | 131 | |
102 | #: src/elektroid.c:1635 | |
132 | #: src/elektroid.c:1568 | |
103 | 133 | #, c-format |
104 | 134 | msgid "Error while creating dir “%s”: %s." |
105 | 135 | msgstr "" |
106 | 136 | |
107 | #: src/elektroid.c:1797 | |
137 | #: src/elektroid.c:1640 | |
108 | 138 | msgid "Queued" |
109 | 139 | msgstr "" |
110 | 140 | |
111 | #: src/elektroid.c:1799 | |
141 | #: src/elektroid.c:1642 | |
112 | 142 | msgid "Running" |
113 | 143 | msgstr "" |
114 | 144 | |
115 | #: src/elektroid.c:1801 | |
145 | #: src/elektroid.c:1644 | |
116 | 146 | msgid "Completed" |
117 | 147 | msgstr "" |
118 | 148 | |
119 | #: src/elektroid.c:1803 | |
149 | #: src/elektroid.c:1646 | |
120 | 150 | msgid "Completed with errors" |
121 | 151 | msgstr "" |
122 | 152 | |
123 | #: src/elektroid.c:1805 | |
153 | #: src/elektroid.c:1648 | |
124 | 154 | msgid "Canceled" |
125 | 155 | msgstr "" |
126 | 156 | |
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 | |
132 | 158 | msgid "Upload" |
133 | 159 | msgstr "" |
134 | 160 | |
135 | #: src/elektroid.c:1819 | |
161 | #: src/elektroid.c:1662 | |
136 | 162 | msgid "Download" |
137 | 163 | msgstr "" |
138 | 164 | |
139 | #: src/elektroid.c:2613 src/elektroid.c:2643 | |
165 | #: src/elektroid.c:2518 src/elektroid.c:2559 | |
140 | 166 | #, c-format |
141 | 167 | msgid "Error while moving from “%s” to “%s”: %s." |
142 | 168 | msgstr "" |
143 | 169 | |
144 | #: res/gui.glade:55 | |
170 | #: res/gui.glade:70 | |
145 | 171 | msgid "Upload Selection" |
146 | 172 | msgstr "" |
147 | 173 | |
148 | #: res/gui.glade:70 | |
174 | #: res/gui.glade:85 | |
149 | 175 | msgid "Play" |
150 | 176 | msgstr "" |
151 | 177 | |
152 | #: res/gui.glade:84 | |
178 | #: res/gui.glade:99 | |
153 | 179 | msgid "Open With External Editor" |
154 | 180 | msgstr "" |
155 | 181 | |
156 | #: res/gui.glade:92 | |
182 | #: res/gui.glade:107 | |
157 | 183 | msgid "Show in File Manager" |
158 | 184 | msgstr "" |
159 | 185 | |
160 | #: res/gui.glade:115 res/gui.glade:164 | |
186 | #: res/gui.glade:139 res/gui.glade:202 | |
161 | 187 | msgid "Delete" |
162 | 188 | msgstr "" |
163 | 189 | |
164 | #: res/gui.glade:140 | |
190 | #: res/gui.glade:168 | |
165 | 191 | msgid "Download Selection" |
166 | 192 | msgstr "" |
167 | 193 | |
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 | |
173 | 199 | msgid "translator-credits" |
174 | 200 | msgstr "" |
175 | 201 | |
176 | #: res/gui.glade:250 | |
202 | #: res/gui.glade:289 | |
177 | 203 | msgid "_Receive SysEx" |
178 | 204 | msgstr "" |
179 | 205 | |
180 | #: res/gui.glade:263 | |
206 | #: res/gui.glade:302 | |
181 | 207 | msgid "_Send SysEx" |
182 | 208 | msgstr "" |
183 | 209 | |
184 | #: res/gui.glade:287 | |
210 | #: res/gui.glade:326 | |
185 | 211 | msgid "OS _Upgrade" |
186 | 212 | msgstr "" |
187 | 213 | |
188 | #: res/gui.glade:311 | |
214 | #: res/gui.glade:350 | |
189 | 215 | msgid "_About" |
190 | 216 | msgstr "" |
191 | 217 | |
192 | #: res/gui.glade:424 res/gui.glade:607 | |
218 | #: res/gui.glade:434 res/gui.glade:583 | |
193 | 219 | msgid "Go to Parent Directory" |
194 | 220 | msgstr "" |
195 | 221 | |
196 | #: res/gui.glade:466 res/gui.glade:649 | |
222 | #: res/gui.glade:455 res/gui.glade:604 | |
197 | 223 | msgid "Refresh Directory" |
198 | 224 | msgstr "" |
199 | 225 | |
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 | |
201 | 227 | msgid "Name" |
202 | 228 | msgstr "" |
203 | 229 | |
204 | #: res/gui.glade:544 res/gui.glade:727 | |
230 | #: res/gui.glade:526 res/gui.glade:685 | |
205 | 231 | msgid "Size" |
206 | 232 | msgstr "" |
207 | 233 | |
208 | #: res/gui.glade:780 | |
234 | #: res/gui.glade:738 | |
209 | 235 | msgid "Refresh Devices" |
210 | 236 | msgstr "" |
211 | 237 | |
212 | 238 | #. 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 | |
214 | 240 | msgid "Auto play" |
215 | 241 | msgstr "" |
216 | 242 | |
217 | #: res/gui.glade:1092 | |
243 | #: res/gui.glade:1088 | |
218 | 244 | msgid "Status" |
219 | 245 | msgstr "" |
220 | 246 | |
221 | #: res/gui.glade:1103 | |
247 | #: res/gui.glade:1099 | |
222 | 248 | msgid "Type" |
223 | 249 | msgstr "" |
224 | 250 | |
225 | #: res/gui.glade:1114 | |
251 | #: res/gui.glade:1120 | |
226 | 252 | msgid "Source" |
227 | 253 | msgstr "" |
228 | 254 | |
229 | #: res/gui.glade:1128 | |
255 | #: res/gui.glade:1134 | |
230 | 256 | msgid "Destination" |
231 | 257 | msgstr "" |
232 | 258 | |
233 | #: res/gui.glade:1143 | |
259 | #: res/gui.glade:1149 | |
234 | 260 | msgid "Progress" |
235 | 261 | msgstr "" |
236 | 262 | |
237 | #: res/gui.glade:1175 | |
263 | #: res/gui.glade:1181 | |
238 | 264 | msgid "Cancel Tasks" |
239 | 265 | msgstr "" |
240 | 266 | |
241 | #: res/gui.glade:1196 | |
267 | #: res/gui.glade:1202 | |
242 | 268 | msgid "Remove Queued Tasks" |
243 | 269 | msgstr "" |
244 | 270 | |
245 | #: res/gui.glade:1217 | |
271 | #: res/gui.glade:1223 | |
246 | 272 | msgid "Clear Finished Tasks" |
247 | 273 | msgstr "" |
6 | 6 | msgstr "" |
7 | 7 | "Project-Id-Version: elektroid 1.4\n" |
8 | 8 | "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" | |
10 | 10 | "PO-Revision-Date: 2020-04-26 13:00+0100\n" |
11 | 11 | "Last-Translator: David García Goñi <dagargo@gmail.com>\n" |
12 | 12 | "Language-Team: English\n" |
16 | 16 | "Content-Transfer-Encoding: 8bit\n" |
17 | 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" |
18 | 18 | |
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 | |
20 | 40 | #, c-format |
21 | 41 | msgid "Connected to %s%s" |
22 | 42 | msgstr "Connected to %s%s" |
23 | 43 | |
24 | #: src/elektroid.c:283 src/elektroid.c:3172 | |
44 | #: src/elektroid.c:406 src/elektroid.c:3215 | |
25 | 45 | msgid "Not connected" |
26 | 46 | msgstr "Not connected" |
27 | 47 | |
28 | #: src/elektroid.c:424 | |
48 | #: src/elektroid.c:549 | |
29 | 49 | msgid "Waiting..." |
30 | 50 | msgstr "Waiting..." |
31 | 51 | |
32 | #: src/elektroid.c:427 | |
52 | #: src/elektroid.c:552 | |
33 | 53 | msgid "Sending..." |
34 | 54 | msgstr "Sending..." |
35 | 55 | |
36 | #: src/elektroid.c:431 | |
56 | #: src/elektroid.c:556 | |
37 | 57 | msgid "Receiving..." |
38 | 58 | msgstr "Receiving..." |
39 | 59 | |
40 | #: src/elektroid.c:499 | |
60 | #: src/elektroid.c:624 | |
41 | 61 | msgid "Receive SysEx" |
42 | 62 | msgstr "Receive SysEx" |
43 | 63 | |
44 | #: src/elektroid.c:521 | |
64 | #: src/elektroid.c:648 | |
45 | 65 | msgid "Save SysEx" |
46 | 66 | msgstr "Save SysEx" |
47 | 67 | |
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 | |
49 | 69 | msgid "_Cancel" |
50 | 70 | msgstr "_Cancel" |
51 | 71 | |
52 | #: src/elektroid.c:526 | |
72 | #: src/elektroid.c:653 | |
53 | 73 | msgid "_Save" |
54 | 74 | msgstr "_Save" |
55 | 75 | |
56 | #: src/elektroid.c:530 | |
76 | #: src/elektroid.c:657 | |
57 | 77 | msgid "Received SysEx" |
58 | 78 | msgstr "Received SysEx" |
59 | 79 | |
60 | #: src/elektroid.c:535 src/elektroid.c:635 | |
80 | #: src/elektroid.c:662 src/elektroid.c:753 | |
61 | 81 | msgid "SysEx Files" |
62 | 82 | msgstr "SysEx Files" |
63 | 83 | |
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 | |
65 | 90 | msgid "Open SysEx" |
66 | 91 | msgstr "Open SysEx" |
67 | 92 | |
68 | #: src/elektroid.c:631 | |
93 | #: src/elektroid.c:749 | |
69 | 94 | msgid "_Open" |
70 | 95 | msgstr "_Open" |
71 | 96 | |
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 | |
73 | 103 | msgid "Send SysEx" |
74 | 104 | msgstr "Send SysEx" |
75 | 105 | |
76 | #: src/elektroid.c:779 | |
106 | #: src/elektroid.c:882 | |
77 | 107 | #, c-format |
78 | 108 | msgid "Error while deleting “%s”: %s." |
79 | 109 | msgstr "Error while deleting “%s”: %s." |
80 | 110 | |
81 | #: src/elektroid.c:811 | |
111 | #: src/elektroid.c:914 | |
82 | 112 | msgid "Are you sure you want to delete the selected items?" |
83 | 113 | msgstr "Are you sure you want to delete the selected items?" |
84 | 114 | |
85 | #: src/elektroid.c:813 | |
115 | #: src/elektroid.c:916 | |
86 | 116 | msgid "_Delete" |
87 | 117 | msgstr "_Delete" |
88 | 118 | |
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 | |
90 | 120 | msgid "Rename" |
91 | 121 | msgstr "Rename" |
92 | 122 | |
93 | #: src/elektroid.c:885 | |
123 | #: src/elektroid.c:987 | |
94 | 124 | #, c-format |
95 | 125 | msgid "Error while renaming to “%s”: %s." |
96 | 126 | msgstr "Error while renaming to “%s”: %s." |
97 | 127 | |
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 | |
99 | 129 | msgid "Add Directory" |
100 | 130 | msgstr "Add Directory" |
101 | 131 | |
102 | #: src/elektroid.c:1635 | |
132 | #: src/elektroid.c:1568 | |
103 | 133 | #, c-format |
104 | 134 | msgid "Error while creating dir “%s”: %s." |
105 | 135 | msgstr "Error while creating dir “%s”: %s." |
106 | 136 | |
107 | #: src/elektroid.c:1797 | |
137 | #: src/elektroid.c:1640 | |
108 | 138 | msgid "Queued" |
109 | 139 | msgstr "Queued" |
110 | 140 | |
111 | #: src/elektroid.c:1799 | |
141 | #: src/elektroid.c:1642 | |
112 | 142 | msgid "Running" |
113 | 143 | msgstr "Running" |
114 | 144 | |
115 | #: src/elektroid.c:1801 | |
145 | #: src/elektroid.c:1644 | |
116 | 146 | msgid "Completed" |
117 | 147 | msgstr "Completed" |
118 | 148 | |
119 | #: src/elektroid.c:1803 | |
149 | #: src/elektroid.c:1646 | |
120 | 150 | msgid "Completed with errors" |
121 | 151 | msgstr "Completed with errors" |
122 | 152 | |
123 | #: src/elektroid.c:1805 | |
153 | #: src/elektroid.c:1648 | |
124 | 154 | msgid "Canceled" |
125 | 155 | msgstr "Canceled" |
126 | 156 | |
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 | |
132 | 158 | msgid "Upload" |
133 | 159 | msgstr "Upload" |
134 | 160 | |
135 | #: src/elektroid.c:1819 | |
161 | #: src/elektroid.c:1662 | |
136 | 162 | msgid "Download" |
137 | 163 | msgstr "Download" |
138 | 164 | |
139 | #: src/elektroid.c:2613 src/elektroid.c:2643 | |
165 | #: src/elektroid.c:2518 src/elektroid.c:2559 | |
140 | 166 | #, c-format |
141 | 167 | msgid "Error while moving from “%s” to “%s”: %s." |
142 | 168 | msgstr "Error while moving from “%s” to “%s”: %s." |
143 | 169 | |
144 | #: res/gui.glade:55 | |
170 | #: res/gui.glade:70 | |
145 | 171 | msgid "Upload Selection" |
146 | 172 | msgstr "Upload Selection" |
147 | 173 | |
148 | #: res/gui.glade:70 | |
174 | #: res/gui.glade:85 | |
149 | 175 | msgid "Play" |
150 | 176 | msgstr "Play" |
151 | 177 | |
152 | #: res/gui.glade:84 | |
178 | #: res/gui.glade:99 | |
153 | 179 | msgid "Open With External Editor" |
154 | 180 | msgstr "Open With External Editor" |
155 | 181 | |
156 | #: res/gui.glade:92 | |
182 | #: res/gui.glade:107 | |
157 | 183 | msgid "Show in File Manager" |
158 | 184 | msgstr "Show in File Manager" |
159 | 185 | |
160 | #: res/gui.glade:115 res/gui.glade:164 | |
186 | #: res/gui.glade:139 res/gui.glade:202 | |
161 | 187 | msgid "Delete" |
162 | 188 | msgstr "Delete" |
163 | 189 | |
164 | #: res/gui.glade:140 | |
190 | #: res/gui.glade:168 | |
165 | 191 | msgid "Download Selection" |
166 | 192 | msgstr "Download selection" |
167 | 193 | |
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 | |
173 | 199 | msgid "translator-credits" |
174 | 200 | msgstr "David García Goñi <dagargo@gmail.com>" |
175 | 201 | |
176 | #: res/gui.glade:250 | |
202 | #: res/gui.glade:289 | |
177 | 203 | msgid "_Receive SysEx" |
178 | 204 | msgstr "_Receive SysEx" |
179 | 205 | |
180 | #: res/gui.glade:263 | |
206 | #: res/gui.glade:302 | |
181 | 207 | msgid "_Send SysEx" |
182 | 208 | msgstr "_Send SysEx" |
183 | 209 | |
184 | #: res/gui.glade:287 | |
210 | #: res/gui.glade:326 | |
185 | 211 | msgid "OS _Upgrade" |
186 | 212 | msgstr "OS _Upgrade" |
187 | 213 | |
188 | #: res/gui.glade:311 | |
214 | #: res/gui.glade:350 | |
189 | 215 | msgid "_About" |
190 | 216 | msgstr "_About" |
191 | 217 | |
192 | #: res/gui.glade:424 res/gui.glade:607 | |
218 | #: res/gui.glade:434 res/gui.glade:583 | |
193 | 219 | msgid "Go to Parent Directory" |
194 | 220 | msgstr "Go to Parent Directory" |
195 | 221 | |
196 | #: res/gui.glade:466 res/gui.glade:649 | |
222 | #: res/gui.glade:455 res/gui.glade:604 | |
197 | 223 | msgid "Refresh Directory" |
198 | 224 | msgstr "Refresh Directory" |
199 | 225 | |
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 | |
201 | 227 | msgid "Name" |
202 | 228 | msgstr "Name" |
203 | 229 | |
204 | #: res/gui.glade:544 res/gui.glade:727 | |
230 | #: res/gui.glade:526 res/gui.glade:685 | |
205 | 231 | msgid "Size" |
206 | 232 | msgstr "Size" |
207 | 233 | |
208 | #: res/gui.glade:780 | |
234 | #: res/gui.glade:738 | |
209 | 235 | msgid "Refresh Devices" |
210 | 236 | msgstr "Refresh Devices" |
211 | 237 | |
212 | 238 | #. 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 | |
214 | 240 | msgid "Auto play" |
215 | 241 | msgstr "Auto play" |
216 | 242 | |
217 | #: res/gui.glade:1092 | |
243 | #: res/gui.glade:1088 | |
218 | 244 | msgid "Status" |
219 | 245 | msgstr "Status" |
220 | 246 | |
221 | #: res/gui.glade:1103 | |
247 | #: res/gui.glade:1099 | |
222 | 248 | msgid "Type" |
223 | 249 | msgstr "Type" |
224 | 250 | |
225 | #: res/gui.glade:1114 | |
251 | #: res/gui.glade:1120 | |
226 | 252 | msgid "Source" |
227 | 253 | msgstr "Source" |
228 | 254 | |
229 | #: res/gui.glade:1128 | |
255 | #: res/gui.glade:1134 | |
230 | 256 | msgid "Destination" |
231 | 257 | msgstr "Destination" |
232 | 258 | |
233 | #: res/gui.glade:1143 | |
259 | #: res/gui.glade:1149 | |
234 | 260 | msgid "Progress" |
235 | 261 | msgstr "Progress" |
236 | 262 | |
237 | #: res/gui.glade:1175 | |
263 | #: res/gui.glade:1181 | |
238 | 264 | msgid "Cancel Tasks" |
239 | 265 | msgstr "Cancel Tasks" |
240 | 266 | |
241 | #: res/gui.glade:1196 | |
267 | #: res/gui.glade:1202 | |
242 | 268 | msgid "Remove Queued Tasks" |
243 | 269 | msgstr "Remove Queued Tasks" |
244 | 270 | |
245 | #: res/gui.glade:1217 | |
271 | #: res/gui.glade:1223 | |
246 | 272 | msgid "Clear Finished Tasks" |
247 | 273 | msgstr "Clear Finished Tasks" |
6 | 6 | msgstr "" |
7 | 7 | "Project-Id-Version: elektroid 1.4\n" |
8 | 8 | "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" | |
10 | 10 | "PO-Revision-Date: 2020-04-26 13:00+0100\n" |
11 | 11 | "Last-Translator: David García Goñi <dagargo@gmail.com>\n" |
12 | 12 | "Language-Team: Spanish\n" |
16 | 16 | "Content-Transfer-Encoding: 8bit\n" |
17 | 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" |
18 | 18 | |
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 | |
20 | 40 | #, c-format |
21 | 41 | msgid "Connected to %s%s" |
22 | 42 | msgstr "Conectado a %s%s" |
23 | 43 | |
24 | #: src/elektroid.c:283 src/elektroid.c:3172 | |
44 | #: src/elektroid.c:406 src/elektroid.c:3215 | |
25 | 45 | msgid "Not connected" |
26 | 46 | msgstr "No conectado" |
27 | 47 | |
28 | #: src/elektroid.c:424 | |
48 | #: src/elektroid.c:549 | |
29 | 49 | msgid "Waiting..." |
30 | 50 | msgstr "Esperando..." |
31 | 51 | |
32 | #: src/elektroid.c:427 | |
52 | #: src/elektroid.c:552 | |
33 | 53 | msgid "Sending..." |
34 | 54 | msgstr "Enviando..." |
35 | 55 | |
36 | #: src/elektroid.c:431 | |
56 | #: src/elektroid.c:556 | |
37 | 57 | msgid "Receiving..." |
38 | 58 | msgstr "Recibiendo..." |
39 | 59 | |
40 | #: src/elektroid.c:499 | |
60 | #: src/elektroid.c:624 | |
41 | 61 | msgid "Receive SysEx" |
42 | 62 | msgstr "Recibir SysEx" |
43 | 63 | |
44 | #: src/elektroid.c:521 | |
64 | #: src/elektroid.c:648 | |
45 | 65 | msgid "Save SysEx" |
46 | 66 | msgstr "Guardar SysEx" |
47 | 67 | |
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 | |
49 | 69 | msgid "_Cancel" |
50 | 70 | msgstr "_Cancelar" |
51 | 71 | |
52 | #: src/elektroid.c:526 | |
72 | #: src/elektroid.c:653 | |
53 | 73 | msgid "_Save" |
54 | 74 | msgstr "_Guardar" |
55 | 75 | |
56 | #: src/elektroid.c:530 | |
76 | #: src/elektroid.c:657 | |
57 | 77 | msgid "Received SysEx" |
58 | 78 | msgstr "SysEx recibido" |
59 | 79 | |
60 | #: src/elektroid.c:535 src/elektroid.c:635 | |
80 | #: src/elektroid.c:662 src/elektroid.c:753 | |
61 | 81 | msgid "SysEx Files" |
62 | 82 | msgstr "Archivos SysEx" |
63 | 83 | |
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 | |
65 | 90 | msgid "Open SysEx" |
66 | 91 | msgstr "Abrir SysEx" |
67 | 92 | |
68 | #: src/elektroid.c:631 | |
93 | #: src/elektroid.c:749 | |
69 | 94 | msgid "_Open" |
70 | 95 | msgstr "_Abrir" |
71 | 96 | |
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 | |
73 | 103 | msgid "Send SysEx" |
74 | 104 | msgstr "Enviar SysEx" |
75 | 105 | |
76 | #: src/elektroid.c:779 | |
106 | #: src/elektroid.c:882 | |
77 | 107 | #, c-format |
78 | 108 | msgid "Error while deleting “%s”: %s." |
79 | 109 | msgstr "Error al eliminar «%s»: %s." |
80 | 110 | |
81 | #: src/elektroid.c:811 | |
111 | #: src/elektroid.c:914 | |
82 | 112 | msgid "Are you sure you want to delete the selected items?" |
83 | 113 | msgstr "¿Está seguro de que quiere eliminar los elementos seleccionados?" |
84 | 114 | |
85 | #: src/elektroid.c:813 | |
115 | #: src/elektroid.c:916 | |
86 | 116 | msgid "_Delete" |
87 | 117 | msgstr "_Eliminar" |
88 | 118 | |
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 | |
90 | 120 | msgid "Rename" |
91 | 121 | msgstr "Renombrar" |
92 | 122 | |
93 | #: src/elektroid.c:885 | |
123 | #: src/elektroid.c:987 | |
94 | 124 | #, c-format |
95 | 125 | msgid "Error while renaming to “%s”: %s." |
96 | 126 | msgstr "Error al renombrar a «%s»: %s." |
97 | 127 | |
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 | |
99 | 129 | msgid "Add Directory" |
100 | 130 | msgstr "Añadir directorio" |
101 | 131 | |
102 | #: src/elektroid.c:1635 | |
132 | #: src/elektroid.c:1568 | |
103 | 133 | #, c-format |
104 | 134 | msgid "Error while creating dir “%s”: %s." |
105 | 135 | msgstr "Error al crear el directorio «%s»: %s." |
106 | 136 | |
107 | #: src/elektroid.c:1797 | |
137 | #: src/elektroid.c:1640 | |
108 | 138 | msgid "Queued" |
109 | 139 | msgstr "Encolada" |
110 | 140 | |
111 | #: src/elektroid.c:1799 | |
141 | #: src/elektroid.c:1642 | |
112 | 142 | msgid "Running" |
113 | 143 | msgstr "Ejecutando" |
114 | 144 | |
115 | #: src/elektroid.c:1801 | |
145 | #: src/elektroid.c:1644 | |
116 | 146 | msgid "Completed" |
117 | 147 | msgstr "Completada" |
118 | 148 | |
119 | #: src/elektroid.c:1803 | |
149 | #: src/elektroid.c:1646 | |
120 | 150 | msgid "Completed with errors" |
121 | 151 | msgstr "Completada con errores" |
122 | 152 | |
123 | #: src/elektroid.c:1805 | |
153 | #: src/elektroid.c:1648 | |
124 | 154 | msgid "Canceled" |
125 | 155 | msgstr "Cancelada" |
126 | 156 | |
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 | |
132 | 158 | msgid "Upload" |
133 | 159 | msgstr "Carga" |
134 | 160 | |
135 | #: src/elektroid.c:1819 | |
161 | #: src/elektroid.c:1662 | |
136 | 162 | msgid "Download" |
137 | 163 | msgstr "Descarga" |
138 | 164 | |
139 | #: src/elektroid.c:2613 src/elektroid.c:2643 | |
165 | #: src/elektroid.c:2518 src/elektroid.c:2559 | |
140 | 166 | #, c-format |
141 | 167 | msgid "Error while moving from “%s” to “%s”: %s." |
142 | 168 | msgstr "Error al mover de «%s» a «%s»: %s." |
143 | 169 | |
144 | #: res/gui.glade:55 | |
170 | #: res/gui.glade:70 | |
145 | 171 | msgid "Upload Selection" |
146 | 172 | msgstr "Cargar selección" |
147 | 173 | |
148 | #: res/gui.glade:70 | |
174 | #: res/gui.glade:85 | |
149 | 175 | msgid "Play" |
150 | 176 | msgstr "Reproducir" |
151 | 177 | |
152 | #: res/gui.glade:84 | |
178 | #: res/gui.glade:99 | |
153 | 179 | msgid "Open With External Editor" |
154 | 180 | msgstr "Abrir con editor externo" |
155 | 181 | |
156 | #: res/gui.glade:92 | |
182 | #: res/gui.glade:107 | |
157 | 183 | msgid "Show in File Manager" |
158 | 184 | msgstr "Mostrar en gestor de archivos" |
159 | 185 | |
160 | #: res/gui.glade:115 res/gui.glade:164 | |
186 | #: res/gui.glade:139 res/gui.glade:202 | |
161 | 187 | msgid "Delete" |
162 | 188 | msgstr "Eliminar" |
163 | 189 | |
164 | #: res/gui.glade:140 | |
190 | #: res/gui.glade:168 | |
165 | 191 | msgid "Download Selection" |
166 | 192 | msgstr "Descargar selección" |
167 | 193 | |
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 | |
174 | 199 | msgid "translator-credits" |
175 | 200 | msgstr "David García Goñi <dagargo@gmail.com>" |
176 | 201 | |
177 | #: res/gui.glade:250 | |
202 | #: res/gui.glade:289 | |
178 | 203 | msgid "_Receive SysEx" |
179 | 204 | msgstr "_Recibir SysEx" |
180 | 205 | |
181 | #: res/gui.glade:263 | |
206 | #: res/gui.glade:302 | |
182 | 207 | msgid "_Send SysEx" |
183 | 208 | msgstr "_Enviar SysEx" |
184 | 209 | |
185 | #: res/gui.glade:287 | |
210 | #: res/gui.glade:326 | |
186 | 211 | msgid "OS _Upgrade" |
187 | 212 | msgstr "Actualizar _SO" |
188 | 213 | |
189 | #: res/gui.glade:311 | |
214 | #: res/gui.glade:350 | |
190 | 215 | msgid "_About" |
191 | 216 | msgstr "_Acerca de" |
192 | 217 | |
193 | #: res/gui.glade:424 res/gui.glade:607 | |
218 | #: res/gui.glade:434 res/gui.glade:583 | |
194 | 219 | msgid "Go to Parent Directory" |
195 | 220 | msgstr "Ir al directorio padre" |
196 | 221 | |
197 | #: res/gui.glade:466 res/gui.glade:649 | |
222 | #: res/gui.glade:455 res/gui.glade:604 | |
198 | 223 | msgid "Refresh Directory" |
199 | 224 | msgstr "Actualizar directorio" |
200 | 225 | |
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 | |
202 | 227 | msgid "Name" |
203 | 228 | msgstr "Nombre" |
204 | 229 | |
205 | #: res/gui.glade:544 res/gui.glade:727 | |
230 | #: res/gui.glade:526 res/gui.glade:685 | |
206 | 231 | msgid "Size" |
207 | 232 | msgstr "Tamaño" |
208 | 233 | |
209 | #: res/gui.glade:780 | |
234 | #: res/gui.glade:738 | |
210 | 235 | msgid "Refresh Devices" |
211 | 236 | msgstr "Actualizar dispositivos" |
212 | 237 | |
213 | 238 | #. 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 | |
215 | 240 | msgid "Auto play" |
216 | 241 | msgstr "" |
217 | 242 | "Reproducción\n" |
218 | 243 | "automática" |
219 | 244 | |
220 | #: res/gui.glade:1092 | |
245 | #: res/gui.glade:1088 | |
221 | 246 | msgid "Status" |
222 | 247 | msgstr "Estado" |
223 | 248 | |
224 | #: res/gui.glade:1103 | |
249 | #: res/gui.glade:1099 | |
225 | 250 | msgid "Type" |
226 | 251 | msgstr "Tipo" |
227 | 252 | |
228 | #: res/gui.glade:1114 | |
253 | #: res/gui.glade:1120 | |
229 | 254 | msgid "Source" |
230 | 255 | msgstr "Origen" |
231 | 256 | |
232 | #: res/gui.glade:1128 | |
257 | #: res/gui.glade:1134 | |
233 | 258 | msgid "Destination" |
234 | 259 | msgstr "Destino" |
235 | 260 | |
236 | #: res/gui.glade:1143 | |
261 | #: res/gui.glade:1149 | |
237 | 262 | msgid "Progress" |
238 | 263 | msgstr "Progreso" |
239 | 264 | |
240 | #: res/gui.glade:1175 | |
265 | #: res/gui.glade:1181 | |
241 | 266 | msgid "Cancel Tasks" |
242 | 267 | msgstr "Cancelar tareas" |
243 | 268 | |
244 | #: res/gui.glade:1196 | |
269 | #: res/gui.glade:1202 | |
245 | 270 | msgid "Remove Queued Tasks" |
246 | 271 | msgstr "Eliminar tareas encoladas" |
247 | 272 | |
248 | #: res/gui.glade:1217 | |
273 | #: res/gui.glade:1223 | |
249 | 274 | msgid "Clear Finished Tasks" |
250 | 275 | msgstr "Limpiar tareas terminadas" |
0 | 0 | # French GUI translation for Elektroid. |
1 | # Copyright (C) 2019-2020 Olivier Humbert | |
1 | # Copyright (C) 2019-2021 Olivier Humbert | |
2 | 2 | # 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. | |
4 | 4 | # |
5 | 5 | msgid "" |
6 | 6 | msgstr "" |
7 | "Project-Id-Version: elektroid 1.4\n" | |
7 | "Project-Id-Version: elektroid 2.0\n" | |
8 | 8 | "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" | |
11 | 11 | "Last-Translator: Olivier Humbert <trebmuh@tuxfamily.org>\n" |
12 | 12 | "Language-Team: French\n" |
13 | 13 | "Language: fr\n" |
16 | 16 | "Content-Transfer-Encoding: 8bit\n" |
17 | 17 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" |
18 | 18 | |
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 | |
20 | 40 | #, c-format |
21 | 41 | msgid "Connected to %s%s" |
22 | 42 | msgstr "Connecté à %s%s" |
23 | 43 | |
24 | #: src/elektroid.c:283 src/elektroid.c:3172 | |
44 | #: src/elektroid.c:406 src/elektroid.c:3215 | |
25 | 45 | msgid "Not connected" |
26 | 46 | msgstr "Non connecté" |
27 | 47 | |
28 | #: src/elektroid.c:424 | |
48 | #: src/elektroid.c:549 | |
29 | 49 | msgid "Waiting..." |
30 | 50 | msgstr "En attente..." |
31 | 51 | |
32 | #: src/elektroid.c:427 | |
52 | #: src/elektroid.c:552 | |
33 | 53 | msgid "Sending..." |
34 | 54 | msgstr "Envoi en cours..." |
35 | 55 | |
36 | #: src/elektroid.c:431 | |
56 | #: src/elektroid.c:556 | |
37 | 57 | msgid "Receiving..." |
38 | 58 | msgstr "Réception en cours..." |
39 | 59 | |
40 | #: src/elektroid.c:499 | |
60 | #: src/elektroid.c:624 | |
41 | 61 | msgid "Receive SysEx" |
42 | 62 | msgstr "Réception de SysEx" |
43 | 63 | |
44 | #: src/elektroid.c:521 | |
64 | #: src/elektroid.c:648 | |
45 | 65 | msgid "Save SysEx" |
46 | 66 | msgstr "Sauvegarde de SysEx" |
47 | 67 | |
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 | |
49 | 69 | msgid "_Cancel" |
50 | 70 | msgstr "_Annuler" |
51 | 71 | |
52 | #: src/elektroid.c:526 | |
72 | #: src/elektroid.c:653 | |
53 | 73 | msgid "_Save" |
54 | 74 | msgstr "_Sauvegarder" |
55 | 75 | |
56 | #: src/elektroid.c:530 | |
76 | #: src/elektroid.c:657 | |
57 | 77 | msgid "Received SysEx" |
58 | 78 | msgstr "SysEx reçu" |
59 | 79 | |
60 | #: src/elektroid.c:535 src/elektroid.c:635 | |
80 | #: src/elektroid.c:662 src/elektroid.c:753 | |
61 | 81 | msgid "SysEx Files" |
62 | 82 | msgstr "Fichiers SysEx" |
63 | 83 | |
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 | |
65 | 90 | msgid "Open SysEx" |
66 | 91 | msgstr "Ouvrir SysEx" |
67 | 92 | |
68 | #: src/elektroid.c:631 | |
93 | #: src/elektroid.c:749 | |
69 | 94 | msgid "_Open" |
70 | 95 | msgstr "_Ouvrir" |
71 | 96 | |
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 | |
73 | 103 | msgid "Send SysEx" |
74 | 104 | msgstr "Envoyer SysEx" |
75 | 105 | |
76 | #: src/elektroid.c:779 | |
106 | #: src/elektroid.c:882 | |
77 | 107 | #, c-format |
78 | 108 | msgid "Error while deleting “%s”: %s." |
79 | 109 | msgstr "Erreur lors de la suppression de « %s » : %s." |
80 | 110 | |
81 | #: src/elektroid.c:811 | |
111 | #: src/elektroid.c:914 | |
82 | 112 | msgid "Are you sure you want to delete the selected items?" |
83 | 113 | msgstr "Souhaitez-vous vraiment supprimer les éléments sélectionnés ?" |
84 | 114 | |
85 | #: src/elektroid.c:813 | |
115 | #: src/elektroid.c:916 | |
86 | 116 | msgid "_Delete" |
87 | 117 | msgstr "_Supprimer" |
88 | 118 | |
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 | |
90 | 120 | msgid "Rename" |
91 | 121 | msgstr "Renommer" |
92 | 122 | |
93 | #: src/elektroid.c:885 | |
123 | #: src/elektroid.c:987 | |
94 | 124 | #, c-format |
95 | 125 | msgid "Error while renaming to “%s”: %s." |
96 | 126 | msgstr "Erreur lors du renommage de « %s » : %s." |
97 | 127 | |
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 | |
99 | 129 | msgid "Add Directory" |
100 | 130 | msgstr "Ajout d'un répertoire" |
101 | 131 | |
102 | #: src/elektroid.c:1635 | |
132 | #: src/elektroid.c:1568 | |
103 | 133 | #, c-format |
104 | 134 | msgid "Error while creating dir “%s”: %s." |
105 | 135 | msgstr "Erreur lors de la création du répertoire « %s » : %s." |
106 | 136 | |
107 | #: src/elektroid.c:1797 | |
137 | #: src/elektroid.c:1640 | |
108 | 138 | 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 | |
112 | 142 | msgid "Running" |
113 | 143 | msgstr "En cours" |
114 | 144 | |
115 | #: src/elektroid.c:1801 | |
145 | #: src/elektroid.c:1644 | |
116 | 146 | msgid "Completed" |
117 | 147 | msgstr "Terminé" |
118 | 148 | |
119 | #: src/elektroid.c:1803 | |
149 | #: src/elektroid.c:1646 | |
120 | 150 | msgid "Completed with errors" |
121 | 151 | msgstr "Terminé avec des erreurs" |
122 | 152 | |
123 | #: src/elektroid.c:1805 | |
153 | #: src/elektroid.c:1648 | |
124 | 154 | msgid "Canceled" |
125 | 155 | msgstr "Annulé" |
126 | 156 | |
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 | |
132 | 158 | msgid "Upload" |
133 | 159 | msgstr "Téléversement" |
134 | 160 | |
135 | #: src/elektroid.c:1819 | |
161 | #: src/elektroid.c:1662 | |
136 | 162 | msgid "Download" |
137 | 163 | msgstr "Téléchargement" |
138 | 164 | |
139 | #: src/elektroid.c:2613 src/elektroid.c:2643 | |
165 | #: src/elektroid.c:2518 src/elektroid.c:2559 | |
140 | 166 | #, c-format |
141 | 167 | msgid "Error while moving from “%s” to “%s”: %s." |
142 | 168 | msgstr "Erreur lors du passage de « %s » à « %s » : %s." |
143 | 169 | |
144 | #: res/gui.glade:55 | |
170 | #: res/gui.glade:70 | |
145 | 171 | msgid "Upload Selection" |
146 | 172 | msgstr "Téléversement de la sélection" |
147 | 173 | |
148 | #: res/gui.glade:70 | |
174 | #: res/gui.glade:85 | |
149 | 175 | msgid "Play" |
150 | 176 | msgstr "Lecture" |
151 | 177 | |
152 | #: res/gui.glade:84 | |
178 | #: res/gui.glade:99 | |
153 | 179 | msgid "Open With External Editor" |
154 | 180 | msgstr "Ouvrir avec un éditeur externe" |
155 | 181 | |
156 | #: res/gui.glade:92 | |
182 | #: res/gui.glade:107 | |
157 | 183 | msgid "Show in File Manager" |
158 | 184 | msgstr "Afficher dans un ge_stionnaire de fichier" |
159 | 185 | |
160 | #: res/gui.glade:115 res/gui.glade:164 | |
186 | #: res/gui.glade:139 res/gui.glade:202 | |
161 | 187 | msgid "Delete" |
162 | 188 | msgstr "Supprimer" |
163 | 189 | |
164 | #: res/gui.glade:140 | |
190 | #: res/gui.glade:168 | |
165 | 191 | msgid "Download Selection" |
166 | 192 | msgstr "Téléchargement de la sélection" |
167 | 193 | |
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 | |
175 | 199 | msgid "translator-credits" |
176 | 200 | msgstr "Olivier Humbert <trebmuh@tuxfamily.org>" |
177 | 201 | |
178 | #: res/gui.glade:250 | |
202 | #: res/gui.glade:289 | |
179 | 203 | msgid "_Receive SysEx" |
180 | 204 | msgstr "_Réception de SysEx" |
181 | 205 | |
182 | #: res/gui.glade:263 | |
206 | #: res/gui.glade:302 | |
183 | 207 | msgid "_Send SysEx" |
184 | 208 | msgstr "Envoi de _Sysex" |
185 | 209 | |
186 | #: res/gui.glade:287 | |
210 | #: res/gui.glade:326 | |
187 | 211 | msgid "OS _Upgrade" |
188 | 212 | msgstr "Mise à jo_ur SE" |
189 | 213 | |
190 | #: res/gui.glade:311 | |
214 | #: res/gui.glade:350 | |
191 | 215 | msgid "_About" |
192 | 216 | msgstr "À _propos" |
193 | 217 | |
194 | #: res/gui.glade:424 res/gui.glade:607 | |
218 | #: res/gui.glade:434 res/gui.glade:583 | |
195 | 219 | msgid "Go to Parent Directory" |
196 | 220 | msgstr "Aller au répertoire parent" |
197 | 221 | |
198 | #: res/gui.glade:466 res/gui.glade:649 | |
222 | #: res/gui.glade:455 res/gui.glade:604 | |
199 | 223 | msgid "Refresh Directory" |
200 | 224 | msgstr "Rafraîchir le répertoire" |
201 | 225 | |
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 | |
203 | 227 | msgid "Name" |
204 | 228 | msgstr "Nom" |
205 | 229 | |
206 | #: res/gui.glade:544 res/gui.glade:727 | |
230 | #: res/gui.glade:526 res/gui.glade:685 | |
207 | 231 | msgid "Size" |
208 | 232 | msgstr "Taille" |
209 | 233 | |
210 | #: res/gui.glade:780 | |
234 | #: res/gui.glade:738 | |
211 | 235 | msgid "Refresh Devices" |
212 | 236 | msgstr "Rafraîchir les périphériques" |
213 | 237 | |
214 | 238 | #. 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 | |
216 | 240 | msgid "Auto play" |
217 | 241 | msgstr "" |
218 | 242 | "Lecture\n" |
219 | 243 | "automatique" |
220 | 244 | |
221 | #: res/gui.glade:1092 | |
245 | #: res/gui.glade:1088 | |
222 | 246 | msgid "Status" |
223 | 247 | msgstr "Statut" |
224 | 248 | |
225 | #: res/gui.glade:1103 | |
249 | #: res/gui.glade:1099 | |
226 | 250 | msgid "Type" |
227 | 251 | msgstr "Type" |
228 | 252 | |
229 | #: res/gui.glade:1114 | |
253 | #: res/gui.glade:1120 | |
230 | 254 | msgid "Source" |
231 | 255 | msgstr "Source" |
232 | 256 | |
233 | #: res/gui.glade:1128 | |
257 | #: res/gui.glade:1134 | |
234 | 258 | msgid "Destination" |
235 | 259 | msgstr "Destination" |
236 | 260 | |
237 | #: res/gui.glade:1143 | |
261 | #: res/gui.glade:1149 | |
238 | 262 | msgid "Progress" |
239 | 263 | msgstr "Progrès" |
240 | 264 | |
241 | #: res/gui.glade:1175 | |
265 | #: res/gui.glade:1181 | |
242 | 266 | msgid "Cancel Tasks" |
243 | 267 | msgstr "Annuler les tâches" |
244 | 268 | |
245 | #: res/gui.glade:1196 | |
269 | #: res/gui.glade:1202 | |
246 | 270 | 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 | |
250 | 274 | msgid "Clear Finished Tasks" |
251 | 275 | 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" |
7 | 7 | metainfo_DATA = elektroid.appdata.xml |
8 | 8 | |
9 | 9 | 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 | |
11 | 11 | |
12 | 12 | gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datarootdir)/icons/hicolor |
13 | 13 |
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-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> |
0 | 0 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> |
1 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | |
2 | ||
3 | 1 | <svg |
4 | 2 | xmlns:dc="http://purl.org/dc/elements/1.1/" |
5 | 3 | xmlns:cc="http://creativecommons.org/ns#" |
14 | 12 | version="1.1" |
15 | 13 | id="svg924" |
16 | 14 | 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)"> | |
18 | 16 | <title |
19 | 17 | id="title2309">elektroid wave symbolic</title> |
20 | 18 | <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> | |
22 | 35 | <sodipodi:namedview |
23 | 36 | id="base" |
24 | 37 | pagecolor="#ffffff" |
26 | 39 | borderopacity="1.0" |
27 | 40 | inkscape:pageopacity="0.0" |
28 | 41 | 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" | |
32 | 45 | inkscape:document-units="px" |
33 | 46 | inkscape:current-layer="layer1" |
34 | 47 | showgrid="true" |
35 | 48 | inkscape:window-width="1680" |
36 | inkscape:window-height="1023" | |
49 | inkscape:window-height="1013" | |
37 | 50 | inkscape:window-x="0" |
38 | 51 | inkscape:window-y="0" |
39 | 52 | inkscape:window-maximized="1" |
40 | inkscape:pagecheckerboard="false"> | |
53 | inkscape:pagecheckerboard="false" | |
54 | inkscape:document-rotation="0"> | |
41 | 55 | <inkscape:grid |
42 | 56 | type="xygrid" |
43 | 57 | id="grid1511" /> |
81 | 95 | inkscape:groupmode="layer" |
82 | 96 | id="layer1" |
83 | 97 | 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" /> | |
519 | 108 | </g> |
520 | 109 | </svg> |
27 | 27 | inkscape:pageopacity="0.0" |
28 | 28 | inkscape:pageshadow="2" |
29 | 29 | inkscape:zoom="32" |
30 | inkscape:cx="9.8604629" | |
31 | inkscape:cy="7.9458677" | |
30 | inkscape:cx="-0.63389357" | |
31 | inkscape:cy="7.6958677" | |
32 | 32 | inkscape:document-units="px" |
33 | 33 | inkscape:current-layer="layer1" |
34 | 34 | showgrid="true" |
82 | 82 | id="layer1" |
83 | 83 | transform="translate(0,-292.76667)"> |
84 | 84 | <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" | |
89 | 207 | x="2.3812499" |
90 | 208 | y="293.29584" /> |
91 | 209 | <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" | |
135 | 260 | 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" | |
158 | 267 | 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" | |
187 | 268 | y="294.61874" /> |
188 | 269 | </g> |
189 | 270 | </svg> |
1 | 1 | Type=Application |
2 | 2 | Name=Elektroid |
3 | 3 | Comment=Sample transfer application for Elektron devices |
4 | Comment[ca]=Aplicació de transferència de mostres per a dispositius Elektron | |
4 | 5 | Comment[de]=Sample Transfer Anwendung für Elektron Instrumente |
5 | 6 | Comment[es]=Aplicación de transferencia de muestras para dispositivos Elektron |
6 | 7 | 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 | |
7 | 9 | Categories=Music;AudioVideo;X-Sound;Audio;X-Alsa |
8 | 10 | Keywords=music;alsa;realtime;standalone; |
9 | 11 | Exec=elektroid |
0 | 0 | <?xml version="1.0" encoding="UTF-8"?> |
1 | <!-- Generated with glade 3.22.1 | |
1 | <!-- Generated with glade 3.38.2 | |
2 | 2 | |
3 | 3 | Copyright (C) David García Goñi |
4 | 4 | |
19 | 19 | |
20 | 20 | --> |
21 | 21 | <interface> |
22 | <requires lib="gtk+" version="3.20"/> | |
22 | <requires lib="gtk+" version="3.24"/> | |
23 | <!-- interface-css-provider-path gui.css --> | |
23 | 24 | <!-- interface-license-type gplv3 --> |
24 | 25 | <!-- interface-name Elektroid --> |
25 | 26 | <!-- interface-description GNU/Linux sample transfer application for Elektron devices --> |
32 | 33 | <column type="gchararray"/> |
33 | 34 | </columns> |
34 | 35 | </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> | |
35 | 46 | <object class="GtkListStore" id="local_list_store"> |
36 | 47 | <columns> |
37 | <!-- column-name type --> | |
48 | <!-- column-name icon --> | |
38 | 49 | <column type="gchararray"/> |
39 | 50 | <!-- column-name name --> |
40 | 51 | <column type="gchararray"/> |
41 | 52 | <!-- column-name size --> |
42 | 53 | <column type="gint"/> |
43 | <!-- column-name size_human --> | |
54 | <!-- column-name size_str --> | |
44 | 55 | <column type="gchararray"/> |
56 | <!-- column-name type --> | |
57 | <column type="gint"/> | |
58 | <!-- column-name index --> | |
59 | <column type="gint"/> | |
45 | 60 | </columns> |
46 | 61 | </object> |
47 | 62 | <object class="GtkMenu" id="local_menu"> |
48 | 63 | <property name="visible">True</property> |
49 | <property name="can_focus">False</property> | |
64 | <property name="can-focus">False</property> | |
50 | 65 | <child> |
51 | 66 | <object class="GtkMenuItem" id="upload_menuitem"> |
52 | 67 | <property name="visible">True</property> |
53 | <property name="can_focus">False</property> | |
68 | <property name="can-focus">False</property> | |
54 | 69 | <property name="label" translatable="yes">Upload Selection</property> |
55 | <property name="use_underline">True</property> | |
70 | <property name="use-underline">True</property> | |
56 | 71 | <accelerator key="Right" signal="activate" modifiers="GDK_CONTROL_MASK"/> |
57 | 72 | </object> |
58 | 73 | </child> |
59 | 74 | <child> |
60 | 75 | <object class="GtkSeparatorMenuItem"> |
61 | 76 | <property name="visible">True</property> |
62 | <property name="can_focus">False</property> | |
77 | <property name="can-focus">False</property> | |
63 | 78 | </object> |
64 | 79 | </child> |
65 | 80 | <child> |
66 | 81 | <object class="GtkMenuItem" id="local_play_menuitem"> |
67 | 82 | <property name="visible">True</property> |
68 | <property name="can_focus">False</property> | |
83 | <property name="can-focus">False</property> | |
69 | 84 | <property name="label" translatable="yes">Play</property> |
70 | <property name="use_underline">True</property> | |
85 | <property name="use-underline">True</property> | |
71 | 86 | </object> |
72 | 87 | </child> |
73 | 88 | <child> |
74 | 89 | <object class="GtkSeparatorMenuItem"> |
75 | 90 | <property name="visible">True</property> |
76 | <property name="can_focus">False</property> | |
91 | <property name="can-focus">False</property> | |
77 | 92 | </object> |
78 | 93 | </child> |
79 | 94 | <child> |
80 | 95 | <object class="GtkMenuItem" id="local_open_menuitem"> |
81 | 96 | <property name="visible">True</property> |
82 | <property name="can_focus">False</property> | |
97 | <property name="can-focus">False</property> | |
83 | 98 | <property name="label" translatable="yes">Open With External Editor</property> |
84 | <property name="use_underline">True</property> | |
99 | <property name="use-underline">True</property> | |
85 | 100 | </object> |
86 | 101 | </child> |
87 | 102 | <child> |
88 | 103 | <object class="GtkMenuItem" id="local_show_menuitem"> |
89 | 104 | <property name="visible">True</property> |
90 | <property name="can_focus">False</property> | |
105 | <property name="can-focus">False</property> | |
91 | 106 | <property name="label" translatable="yes">Show in File Manager</property> |
92 | <property name="use_underline">True</property> | |
107 | <property name="use-underline">True</property> | |
93 | 108 | </object> |
94 | 109 | </child> |
95 | 110 | <child> |
96 | 111 | <object class="GtkSeparatorMenuItem"> |
97 | 112 | <property name="visible">True</property> |
98 | <property name="can_focus">False</property> | |
113 | <property name="can-focus">False</property> | |
99 | 114 | </object> |
100 | 115 | </child> |
101 | 116 | <child> |
102 | 117 | <object class="GtkMenuItem" id="local_rename_menuitem"> |
103 | 118 | <property name="visible">True</property> |
104 | <property name="can_focus">False</property> | |
119 | <property name="can-focus">False</property> | |
105 | 120 | <property name="label" translatable="yes">Rename</property> |
106 | <property name="use_underline">True</property> | |
121 | <property name="use-underline">True</property> | |
107 | 122 | <accelerator key="F2" signal="activate"/> |
108 | 123 | </object> |
109 | 124 | </child> |
110 | 125 | <child> |
111 | 126 | <object class="GtkMenuItem" id="local_delete_menuitem"> |
112 | 127 | <property name="visible">True</property> |
113 | <property name="can_focus">False</property> | |
128 | <property name="can-focus">False</property> | |
114 | 129 | <property name="label" translatable="yes">Delete</property> |
115 | <property name="use_underline">True</property> | |
130 | <property name="use-underline">True</property> | |
116 | 131 | <accelerator key="Delete" signal="activate"/> |
117 | 132 | </object> |
118 | 133 | </child> |
119 | 134 | </object> |
120 | 135 | <object class="GtkListStore" id="remote_list_store"> |
121 | 136 | <columns> |
122 | <!-- column-name type --> | |
137 | <!-- column-name icon --> | |
123 | 138 | <column type="gchararray"/> |
124 | 139 | <!-- column-name name --> |
125 | 140 | <column type="gchararray"/> |
126 | 141 | <!-- column-name size --> |
127 | 142 | <column type="gint"/> |
128 | <!-- column-name human_size --> | |
143 | <!-- column-name size_str --> | |
129 | 144 | <column type="gchararray"/> |
145 | <!-- column-name type --> | |
146 | <column type="gint"/> | |
147 | <!-- column-name index --> | |
148 | <column type="gint"/> | |
130 | 149 | </columns> |
131 | 150 | </object> |
132 | 151 | <object class="GtkMenu" id="remote_menu"> |
133 | 152 | <property name="visible">True</property> |
134 | <property name="can_focus">False</property> | |
153 | <property name="can-focus">False</property> | |
135 | 154 | <child> |
136 | 155 | <object class="GtkMenuItem" id="download_menuitem"> |
137 | 156 | <property name="visible">True</property> |
138 | <property name="can_focus">False</property> | |
157 | <property name="can-focus">False</property> | |
139 | 158 | <property name="label" translatable="yes">Download Selection</property> |
140 | <property name="use_underline">True</property> | |
159 | <property name="use-underline">True</property> | |
141 | 160 | <accelerator key="Left" signal="activate" modifiers="GDK_CONTROL_MASK"/> |
142 | 161 | </object> |
143 | 162 | </child> |
144 | 163 | <child> |
145 | 164 | <object class="GtkSeparatorMenuItem"> |
146 | 165 | <property name="visible">True</property> |
147 | <property name="can_focus">False</property> | |
166 | <property name="can-focus">False</property> | |
148 | 167 | </object> |
149 | 168 | </child> |
150 | 169 | <child> |
151 | 170 | <object class="GtkMenuItem" id="remote_rename_menuitem"> |
152 | 171 | <property name="visible">True</property> |
153 | <property name="can_focus">False</property> | |
172 | <property name="can-focus">False</property> | |
154 | 173 | <property name="label" translatable="yes">Rename</property> |
155 | <property name="use_underline">True</property> | |
174 | <property name="use-underline">True</property> | |
156 | 175 | <accelerator key="F2" signal="activate"/> |
157 | 176 | </object> |
158 | 177 | </child> |
159 | 178 | <child> |
160 | 179 | <object class="GtkMenuItem" id="remote_delete_menuitem"> |
161 | 180 | <property name="visible">True</property> |
162 | <property name="can_focus">False</property> | |
181 | <property name="can-focus">False</property> | |
163 | 182 | <property name="label" translatable="yes">Delete</property> |
164 | <property name="use_underline">True</property> | |
183 | <property name="use-underline">True</property> | |
165 | 184 | <accelerator key="Delete" signal="activate"/> |
166 | 185 | </object> |
167 | 186 | </child> |
182 | 201 | <column type="gchararray"/> |
183 | 202 | <!-- column-name type_human --> |
184 | 203 | <column type="gchararray"/> |
204 | <!-- column-name remote_fs_id --> | |
205 | <column type="gint"/> | |
206 | <!-- column-name remote_fs_icon --> | |
207 | <column type="gchararray"/> | |
185 | 208 | </columns> |
186 | 209 | </object> |
187 | 210 | <object class="GtkAboutDialog" id="about_dialog"> |
188 | <property name="can_focus">False</property> | |
211 | <property name="can-focus">False</property> | |
189 | 212 | <property name="resizable">False</property> |
190 | 213 | <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> | |
194 | 217 | <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> | |
196 | 219 | <property name="website">https://github.com/dagargo/elektroid</property> |
197 | 220 | <property name="authors">David García Goñi<dagargo@gmail.com></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> | |
204 | 224 | <child internal-child="vbox"> |
205 | 225 | <object class="GtkBox"> |
206 | <property name="can_focus">False</property> | |
226 | <property name="can-focus">False</property> | |
207 | 227 | <property name="orientation">vertical</property> |
208 | 228 | <property name="spacing">2</property> |
209 | 229 | <child internal-child="action_area"> |
210 | 230 | <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> | |
213 | 233 | <child> |
214 | 234 | <placeholder/> |
215 | 235 | </child> |
230 | 250 | </child> |
231 | 251 | </object> |
232 | 252 | <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> | |
235 | 255 | <child> |
236 | 256 | <object class="GtkBox"> |
237 | 257 | <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> | |
243 | 263 | <property name="orientation">vertical</property> |
244 | 264 | <child> |
245 | 265 | <object class="GtkModelButton" id="rx_sysex_button"> |
246 | 266 | <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> | |
249 | 269 | <property name="text" translatable="yes">_Receive SysEx</property> |
250 | 270 | </object> |
251 | 271 | <packing> |
257 | 277 | <child> |
258 | 278 | <object class="GtkModelButton" id="tx_sysex_button"> |
259 | 279 | <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> | |
262 | 282 | <property name="text" translatable="yes">_Send SysEx</property> |
263 | 283 | </object> |
264 | 284 | <packing> |
270 | 290 | <child> |
271 | 291 | <object class="GtkSeparator"> |
272 | 292 | <property name="visible">True</property> |
273 | <property name="can_focus">False</property> | |
293 | <property name="can-focus">False</property> | |
274 | 294 | </object> |
275 | 295 | <packing> |
276 | 296 | <property name="expand">False</property> |
281 | 301 | <child> |
282 | 302 | <object class="GtkModelButton" id="os_upgrade_button"> |
283 | 303 | <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> | |
286 | 306 | <property name="text" translatable="yes">OS _Upgrade</property> |
287 | 307 | </object> |
288 | 308 | <packing> |
294 | 314 | <child> |
295 | 315 | <object class="GtkSeparator"> |
296 | 316 | <property name="visible">True</property> |
297 | <property name="can_focus">False</property> | |
317 | <property name="can-focus">False</property> | |
298 | 318 | </object> |
299 | 319 | <packing> |
300 | 320 | <property name="expand">False</property> |
305 | 325 | <child> |
306 | 326 | <object class="GtkModelButton" id="about_button"> |
307 | 327 | <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> | |
310 | 330 | <property name="text" translatable="yes">_About</property> |
311 | 331 | </object> |
312 | 332 | <packing> |
323 | 343 | </child> |
324 | 344 | </object> |
325 | 345 | <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> | |
352 | 348 | <child> |
353 | 349 | <object class="GtkBox"> |
354 | 350 | <property name="visible">True</property> |
355 | <property name="can_focus">False</property> | |
351 | <property name="can-focus">False</property> | |
356 | 352 | <property name="orientation">vertical</property> |
357 | 353 | <child> |
358 | 354 | <object class="GtkPaned"> |
359 | 355 | <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> | |
364 | 360 | <property name="hexpand">True</property> |
365 | 361 | <property name="vexpand">True</property> |
366 | 362 | <property name="orientation">vertical</property> |
367 | 363 | <child> |
368 | 364 | <object class="GtkBox"> |
369 | 365 | <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> | |
372 | 368 | <property name="hexpand">True</property> |
373 | 369 | <property name="vexpand">True</property> |
374 | 370 | <property name="orientation">vertical</property> |
375 | 371 | <property name="spacing">6</property> |
376 | 372 | <child> |
373 | <!-- n-columns=2 n-rows=2 --> | |
377 | 374 | <object class="GtkGrid"> |
378 | 375 | <property name="visible">True</property> |
379 | <property name="can_focus">False</property> | |
376 | <property name="can-focus">False</property> | |
380 | 377 | <property name="hexpand">True</property> |
381 | 378 | <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> | |
384 | 381 | <child> |
385 | 382 | <object class="GtkBox"> |
386 | 383 | <property name="visible">True</property> |
387 | <property name="can_focus">False</property> | |
384 | <property name="can-focus">False</property> | |
388 | 385 | <property name="hexpand">True</property> |
389 | 386 | <property name="vexpand">True</property> |
390 | 387 | <property name="orientation">vertical</property> |
392 | 389 | <child> |
393 | 390 | <object class="GtkBox"> |
394 | 391 | <property name="visible">True</property> |
395 | <property name="can_focus">False</property> | |
392 | <property name="can-focus">False</property> | |
396 | 393 | <property name="hexpand">True</property> |
397 | 394 | <property name="spacing">6</property> |
398 | 395 | <child> |
399 | 396 | <object class="GtkEntry" id="local_dir_entry"> |
400 | 397 | <property name="visible">True</property> |
401 | <property name="can_focus">True</property> | |
398 | <property name="can-focus">True</property> | |
402 | 399 | <property name="hexpand">True</property> |
403 | 400 | <property name="editable">False</property> |
404 | 401 | </object> |
409 | 406 | </packing> |
410 | 407 | </child> |
411 | 408 | <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"> | |
420 | 417 | <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> | |
479 | 421 | </child> |
480 | 422 | </object> |
481 | 423 | <packing> |
484 | 426 | <property name="position">1</property> |
485 | 427 | </packing> |
486 | 428 | </child> |
429 | <child> | |
430 | <object class="GtkButton" id="local_add_dir_button"> | |
431 | <property name="name">local_up_button</property> | |
432 | <property name="visible">True</property> | |
433 | <property name="can-focus">True</property> | |
434 | <property name="receives-default">True</property> | |
435 | <property name="tooltip-text" translatable="yes">Add Directory</property> | |
436 | <child> | |
437 | <object class="GtkImage"> | |
438 | <property name="visible">True</property> | |
439 | <property name="can-focus">False</property> | |
440 | <property name="icon-name">folder-new-symbolic</property> | |
441 | </object> | |
442 | </child> | |
443 | </object> | |
444 | <packing> | |
445 | <property name="expand">False</property> | |
446 | <property name="fill">True</property> | |
447 | <property name="position">2</property> | |
448 | </packing> | |
449 | </child> | |
450 | <child> | |
451 | <object class="GtkButton" id="local_refresh_button"> | |
452 | <property name="name">local_refresh_button</property> | |
453 | <property name="visible">True</property> | |
454 | <property name="can-focus">True</property> | |
455 | <property name="receives-default">True</property> | |
456 | <property name="tooltip-text" translatable="yes">Refresh Directory</property> | |
457 | <child> | |
458 | <object class="GtkImage"> | |
459 | <property name="visible">True</property> | |
460 | <property name="can-focus">False</property> | |
461 | <property name="icon-name">view-refresh-symbolic</property> | |
462 | </object> | |
463 | </child> | |
464 | </object> | |
465 | <packing> | |
466 | <property name="expand">False</property> | |
467 | <property name="fill">True</property> | |
468 | <property name="position">3</property> | |
469 | </packing> | |
470 | </child> | |
487 | 471 | </object> |
488 | 472 | <packing> |
489 | 473 | <property name="expand">False</property> |
493 | 477 | </child> |
494 | 478 | <child> |
495 | 479 | <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> | |
498 | 482 | <property name="visible">True</property> |
499 | <property name="can_focus">True</property> | |
483 | <property name="can-focus">True</property> | |
500 | 484 | <property name="hexpand">True</property> |
501 | 485 | <property name="vexpand">True</property> |
502 | <property name="shadow_type">in</property> | |
486 | <property name="shadow-type">in</property> | |
503 | 487 | <child> |
504 | 488 | <object class="GtkTreeView" id="local_tree_view"> |
505 | 489 | <property name="name">local_tree_view</property> |
506 | 490 | <property name="visible">True</property> |
507 | <property name="can_focus">True</property> | |
491 | <property name="can-focus">True</property> | |
508 | 492 | <property name="hexpand">True</property> |
509 | 493 | <property name="vexpand">True</property> |
510 | 494 | <property name="model">local_list_store</property> |
511 | <property name="search_column">1</property> | |
495 | <property name="search-column">1</property> | |
512 | 496 | <child internal-child="selection"> |
513 | 497 | <object class="GtkTreeSelection"> |
514 | 498 | <property name="mode">multiple</property> |
529 | 513 | <property name="title" translatable="yes">Name</property> |
530 | 514 | <property name="expand">True</property> |
531 | 515 | <child> |
532 | <object class="GtkCellRendererText" id="local_name_cell_renderer_text"> | |
516 | <object class="GtkCellRendererText"> | |
533 | 517 | <property name="ellipsize">middle</property> |
534 | 518 | </object> |
535 | 519 | <attributes> |
560 | 544 | </child> |
561 | 545 | </object> |
562 | 546 | <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> | |
565 | 549 | </packing> |
566 | 550 | </child> |
567 | 551 | <child> |
568 | 552 | <object class="GtkBox" id="remote_box"> |
569 | 553 | <property name="visible">True</property> |
570 | <property name="can_focus">False</property> | |
554 | <property name="can-focus">False</property> | |
571 | 555 | <property name="hexpand">True</property> |
572 | 556 | <property name="vexpand">True</property> |
573 | 557 | <property name="orientation">vertical</property> |
575 | 559 | <child> |
576 | 560 | <object class="GtkBox"> |
577 | 561 | <property name="visible">True</property> |
578 | <property name="can_focus">False</property> | |
562 | <property name="can-focus">False</property> | |
579 | 563 | <property name="hexpand">True</property> |
580 | 564 | <property name="spacing">6</property> |
581 | 565 | <child> |
582 | 566 | <object class="GtkEntry" id="remote_dir_entry"> |
583 | 567 | <property name="visible">True</property> |
584 | <property name="can_focus">True</property> | |
568 | <property name="can-focus">True</property> | |
585 | 569 | <property name="hexpand">True</property> |
586 | 570 | <property name="editable">False</property> |
587 | 571 | </object> |
592 | 576 | </packing> |
593 | 577 | </child> |
594 | 578 | <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"> | |
603 | 587 | <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> | |
662 | 591 | </child> |
663 | 592 | </object> |
664 | 593 | <packing> |
667 | 596 | <property name="position">1</property> |
668 | 597 | </packing> |
669 | 598 | </child> |
599 | <child> | |
600 | <object class="GtkButton" id="remote_add_dir_button"> | |
601 | <property name="name">remote_up_button</property> | |
602 | <property name="visible">True</property> | |
603 | <property name="can-focus">True</property> | |
604 | <property name="receives-default">True</property> | |
605 | <property name="tooltip-text" translatable="yes">Add Directory</property> | |
606 | <child> | |
607 | <object class="GtkImage"> | |
608 | <property name="visible">True</property> | |
609 | <property name="can-focus">False</property> | |
610 | <property name="icon-name">folder-new-symbolic</property> | |
611 | </object> | |
612 | </child> | |
613 | </object> | |
614 | <packing> | |
615 | <property name="expand">False</property> | |
616 | <property name="fill">True</property> | |
617 | <property name="position">2</property> | |
618 | </packing> | |
619 | </child> | |
620 | <child> | |
621 | <object class="GtkButton" id="remote_refresh_button"> | |
622 | <property name="name">remote_refresh_button</property> | |
623 | <property name="visible">True</property> | |
624 | <property name="can-focus">True</property> | |
625 | <property name="receives-default">True</property> | |
626 | <property name="tooltip-text" translatable="yes">Refresh Directory</property> | |
627 | <child> | |
628 | <object class="GtkImage"> | |
629 | <property name="visible">True</property> | |
630 | <property name="can-focus">False</property> | |
631 | <property name="icon-name">view-refresh-symbolic</property> | |
632 | </object> | |
633 | </child> | |
634 | </object> | |
635 | <packing> | |
636 | <property name="expand">False</property> | |
637 | <property name="fill">True</property> | |
638 | <property name="position">3</property> | |
639 | </packing> | |
640 | </child> | |
670 | 641 | </object> |
671 | 642 | <packing> |
672 | 643 | <property name="expand">False</property> |
676 | 647 | </child> |
677 | 648 | <child> |
678 | 649 | <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> | |
681 | 652 | <property name="visible">True</property> |
682 | <property name="can_focus">True</property> | |
653 | <property name="can-focus">True</property> | |
683 | 654 | <property name="hexpand">True</property> |
684 | 655 | <property name="vexpand">True</property> |
685 | <property name="shadow_type">in</property> | |
656 | <property name="shadow-type">in</property> | |
686 | 657 | <child> |
687 | 658 | <object class="GtkTreeView" id="remote_tree_view"> |
688 | 659 | <property name="name">remote_tree_view</property> |
689 | 660 | <property name="visible">True</property> |
690 | <property name="can_focus">True</property> | |
661 | <property name="can-focus">True</property> | |
691 | 662 | <property name="hexpand">True</property> |
692 | 663 | <property name="vexpand">True</property> |
693 | 664 | <property name="model">remote_list_store</property> |
694 | <property name="search_column">1</property> | |
665 | <property name="search-column">1</property> | |
695 | 666 | <child internal-child="selection"> |
696 | 667 | <object class="GtkTreeSelection"> |
697 | 668 | <property name="mode">multiple</property> |
703 | 674 | <object class="GtkCellRendererPixbuf"/> |
704 | 675 | <attributes> |
705 | 676 | <attribute name="icon-name">0</attribute> |
677 | </attributes> | |
678 | </child> | |
679 | </object> | |
680 | </child> | |
681 | <child> | |
682 | <object class="GtkTreeViewColumn" id="remote_tree_view_index_column"> | |
683 | <child> | |
684 | <object class="GtkCellRendererText"/> | |
685 | <attributes> | |
686 | <attribute name="text">5</attribute> | |
706 | 687 | </attributes> |
707 | 688 | </child> |
708 | 689 | </object> |
743 | 724 | </child> |
744 | 725 | </object> |
745 | 726 | <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> | |
748 | 729 | </packing> |
749 | 730 | </child> |
750 | 731 | <child> |
751 | 732 | <object class="GtkBox"> |
752 | 733 | <property name="visible">True</property> |
753 | <property name="can_focus">False</property> | |
734 | <property name="can-focus">False</property> | |
754 | 735 | <property name="spacing">6</property> |
755 | 736 | <child> |
756 | 737 | <object class="GtkComboBox" id="devices_combo"> |
757 | 738 | <property name="visible">True</property> |
758 | <property name="can_focus">False</property> | |
739 | <property name="can-focus">False</property> | |
759 | 740 | <property name="model">devices_list_store</property> |
760 | 741 | <child> |
761 | 742 | <object class="GtkCellRendererText"/> |
774 | 755 | <object class="GtkButton" id="refresh_devices_button"> |
775 | 756 | <property name="name">refresh_devices_button</property> |
776 | 757 | <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> | |
780 | 761 | <child> |
781 | 762 | <object class="GtkImage"> |
782 | 763 | <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> | |
785 | 766 | </object> |
786 | 767 | </child> |
787 | 768 | </object> |
791 | 772 | <property name="position">1</property> |
792 | 773 | </packing> |
793 | 774 | </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> | |
794 | 813 | </object> |
795 | 814 | <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> | |
798 | 817 | </packing> |
799 | 818 | </child> |
800 | 819 | <child> |
801 | 820 | <object class="GtkLabel" id="hostname_label"> |
802 | 821 | <property name="visible">True</property> |
803 | <property name="can_focus">False</property> | |
822 | <property name="can-focus">False</property> | |
804 | 823 | <property name="halign">start</property> |
805 | 824 | <property name="hexpand">True</property> |
806 | 825 | </object> |
807 | 826 | <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> | |
810 | 829 | </packing> |
811 | 830 | </child> |
812 | 831 | </object> |
817 | 836 | </packing> |
818 | 837 | </child> |
819 | 838 | <child> |
820 | <object class="GtkBox"> | |
839 | <object class="GtkBox" id="local_audio_box"> | |
821 | 840 | <property name="visible">True</property> |
822 | <property name="can_focus">False</property> | |
841 | <property name="can-focus">False</property> | |
823 | 842 | <property name="hexpand">True</property> |
824 | 843 | <property name="spacing">6</property> |
825 | <property name="baseline_position">bottom</property> | |
844 | <property name="baseline-position">bottom</property> | |
826 | 845 | <child> |
827 | 846 | <object class="GtkBox"> |
828 | 847 | <property name="visible">True</property> |
829 | <property name="can_focus">False</property> | |
848 | <property name="can-focus">False</property> | |
830 | 849 | <property name="halign">start</property> |
831 | 850 | <property name="valign">center</property> |
832 | 851 | <property name="orientation">vertical</property> |
834 | 853 | <child> |
835 | 854 | <object class="GtkBox"> |
836 | 855 | <property name="visible">True</property> |
837 | <property name="can_focus">False</property> | |
856 | <property name="can-focus">False</property> | |
838 | 857 | <property name="spacing">6</property> |
839 | 858 | <child> |
840 | 859 | <object class="GtkSwitch" id="autoplay_switch"> |
841 | 860 | <property name="name">autoplay_switch</property> |
842 | 861 | <property name="visible">True</property> |
843 | <property name="can_focus">True</property> | |
862 | <property name="can-focus">True</property> | |
844 | 863 | <property name="halign">start</property> |
845 | 864 | <property name="valign">center</property> |
846 | 865 | <property name="active">True</property> |
854 | 873 | <child> |
855 | 874 | <object class="GtkLabel"> |
856 | 875 | <property name="visible">True</property> |
857 | <property name="can_focus">False</property> | |
876 | <property name="can-focus">False</property> | |
858 | 877 | <property name="valign">center</property> |
859 | 878 | <property name="label" translatable="yes" comments="It is recommended to split the text in two lines if it is too long">Auto play</property> |
860 | 879 | <property name="wrap">True</property> |
875 | 894 | <child> |
876 | 895 | <object class="GtkBox"> |
877 | 896 | <property name="visible">True</property> |
878 | <property name="can_focus">False</property> | |
897 | <property name="can-focus">False</property> | |
879 | 898 | <property name="halign">center</property> |
880 | 899 | <property name="spacing">6</property> |
881 | 900 | <child> |
882 | 901 | <object class="GtkBox"> |
883 | 902 | <property name="visible">True</property> |
884 | <property name="can_focus">False</property> | |
903 | <property name="can-focus">False</property> | |
885 | 904 | <property name="halign">center</property> |
886 | 905 | <child> |
887 | 906 | <object class="GtkButton" id="play_button"> |
888 | 907 | <property name="name">play_button</property> |
889 | 908 | <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> | |
892 | 911 | <property name="halign">center</property> |
893 | 912 | <property name="valign">center</property> |
894 | 913 | <child> |
895 | 914 | <object class="GtkImage"> |
896 | 915 | <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> | |
899 | 918 | </object> |
900 | 919 | </child> |
901 | 920 | </object> |
909 | 928 | <object class="GtkButton" id="stop_button"> |
910 | 929 | <property name="name">stop_button</property> |
911 | 930 | <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> | |
914 | 933 | <property name="halign">center</property> |
915 | 934 | <property name="valign">center</property> |
916 | 935 | <child> |
917 | 936 | <object class="GtkImage"> |
918 | 937 | <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> | |
921 | 940 | </object> |
922 | 941 | </child> |
923 | 942 | </object> |
931 | 950 | <object class="GtkToggleButton" id="loop_button"> |
932 | 951 | <property name="name">loop_button</property> |
933 | 952 | <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> | |
936 | 955 | <property name="valign">center</property> |
937 | 956 | <child> |
938 | 957 | <object class="GtkImage"> |
939 | 958 | <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> | |
942 | 961 | </object> |
943 | 962 | </child> |
944 | 963 | </object> |
961 | 980 | <child> |
962 | 981 | <object class="GtkVolumeButton" id="volume_button"> |
963 | 982 | <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> | |
967 | 986 | <property name="relief">none</property> |
968 | 987 | <property name="orientation">vertical</property> |
969 | 988 | <property name="icons">audio-volume-muted-symbolic |
972 | 991 | audio-volume-medium-symbolic</property> |
973 | 992 | <child internal-child="plus_button"> |
974 | 993 | <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> | |
977 | 996 | <property name="halign">center</property> |
978 | 997 | <property name="valign">center</property> |
979 | 998 | <property name="relief">none</property> |
981 | 1000 | </child> |
982 | 1001 | <child internal-child="minus_button"> |
983 | 1002 | <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> | |
986 | 1005 | <property name="halign">center</property> |
987 | 1006 | <property name="valign">center</property> |
988 | 1007 | <property name="relief">none</property> |
1015 | 1034 | <child> |
1016 | 1035 | <object class="GtkFrame"> |
1017 | 1036 | <property name="visible">True</property> |
1018 | <property name="can_focus">False</property> | |
1037 | <property name="can-focus">False</property> | |
1019 | 1038 | <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> | |
1023 | 1042 | <child> |
1024 | 1043 | <object class="GtkAlignment"> |
1025 | 1044 | <property name="visible">True</property> |
1026 | <property name="can_focus">False</property> | |
1045 | <property name="can-focus">False</property> | |
1027 | 1046 | <child> |
1028 | 1047 | <object class="GtkDrawingArea" id="waveform_draw_area"> |
1029 | 1048 | <property name="visible">True</property> |
1030 | <property name="can_focus">False</property> | |
1049 | <property name="can-focus">False</property> | |
1031 | 1050 | <property name="hexpand">True</property> |
1032 | 1051 | <style> |
1033 | 1052 | <class name="local"/> |
1038 | 1057 | </child> |
1039 | 1058 | <child type="label"> |
1040 | 1059 | <object class="GtkLabel"> |
1041 | <property name="can_focus">False</property> | |
1060 | <property name="can-focus">False</property> | |
1042 | 1061 | </object> |
1043 | 1062 | </child> |
1044 | 1063 | </object> |
1064 | 1083 | <child> |
1065 | 1084 | <object class="GtkBox"> |
1066 | 1085 | <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> | |
1069 | 1088 | <property name="hexpand">True</property> |
1070 | 1089 | <property name="spacing">6</property> |
1071 | 1090 | <child> |
1072 | 1091 | <object class="GtkScrolledWindow"> |
1073 | 1092 | <property name="visible">True</property> |
1074 | <property name="can_focus">True</property> | |
1093 | <property name="can-focus">True</property> | |
1075 | 1094 | <property name="hexpand">True</property> |
1076 | 1095 | <property name="vexpand">True</property> |
1077 | <property name="shadow_type">in</property> | |
1096 | <property name="shadow-type">in</property> | |
1078 | 1097 | <child> |
1079 | 1098 | <object class="GtkTreeView" id="task_tree_view"> |
1080 | 1099 | <property name="visible">True</property> |
1081 | <property name="can_focus">True</property> | |
1100 | <property name="can-focus">True</property> | |
1082 | 1101 | <property name="model">task_list_store</property> |
1083 | <property name="search_column">0</property> | |
1102 | <property name="search-column">0</property> | |
1084 | 1103 | <child internal-child="selection"> |
1085 | 1104 | <object class="GtkTreeSelection"> |
1086 | 1105 | <property name="mode">none</property> |
1110 | 1129 | </child> |
1111 | 1130 | <child> |
1112 | 1131 | <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"> | |
1113 | 1142 | <property name="title" translatable="yes">Source</property> |
1114 | 1143 | <property name="expand">True</property> |
1115 | 1144 | <child> |
1138 | 1167 | </child> |
1139 | 1168 | <child> |
1140 | 1169 | <object class="GtkTreeViewColumn"> |
1141 | <property name="fixed_width">120</property> | |
1170 | <property name="fixed-width">120</property> | |
1142 | 1171 | <property name="title" translatable="yes">Progress</property> |
1143 | 1172 | <child> |
1144 | 1173 | <object class="GtkCellRendererProgress"/> |
1160 | 1189 | <child> |
1161 | 1190 | <object class="GtkBox"> |
1162 | 1191 | <property name="visible">True</property> |
1163 | <property name="can_focus">False</property> | |
1192 | <property name="can-focus">False</property> | |
1164 | 1193 | <property name="valign">start</property> |
1165 | 1194 | <property name="orientation">vertical</property> |
1166 | 1195 | <property name="spacing">6</property> |
1169 | 1198 | <object class="GtkButton" id="cancel_task_button"> |
1170 | 1199 | <property name="visible">True</property> |
1171 | 1200 | <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> | |
1175 | 1204 | <child> |
1176 | 1205 | <object class="GtkImage"> |
1177 | 1206 | <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> | |
1180 | 1209 | </object> |
1181 | 1210 | </child> |
1182 | 1211 | </object> |
1190 | 1219 | <object class="GtkButton" id="remove_tasks_button"> |
1191 | 1220 | <property name="visible">True</property> |
1192 | 1221 | <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> | |
1196 | 1225 | <child> |
1197 | 1226 | <object class="GtkImage"> |
1198 | 1227 | <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> | |
1201 | 1230 | </object> |
1202 | 1231 | </child> |
1203 | 1232 | </object> |
1211 | 1240 | <object class="GtkButton" id="clear_tasks_button"> |
1212 | 1241 | <property name="visible">True</property> |
1213 | 1242 | <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> | |
1217 | 1246 | <child> |
1218 | 1247 | <object class="GtkImage"> |
1219 | 1248 | <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> | |
1222 | 1251 | </object> |
1223 | 1252 | </child> |
1224 | 1253 | </object> |
1251 | 1280 | <child> |
1252 | 1281 | <object class="GtkStatusbar" id="status_bar"> |
1253 | 1282 | <property name="visible">True</property> |
1254 | <property name="can_focus">False</property> | |
1283 | <property name="can-focus">False</property> | |
1255 | 1284 | <property name="orientation">vertical</property> |
1256 | 1285 | </object> |
1257 | 1286 | <packing> |
1262 | 1291 | </child> |
1263 | 1292 | </object> |
1264 | 1293 | </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> | |
1265 | 1317 | </object> |
1266 | 1318 | <object class="GtkDialog" id="name_dialog"> |
1267 | <property name="can_focus">False</property> | |
1319 | <property name="can-focus">False</property> | |
1268 | 1320 | <property name="resizable">False</property> |
1269 | 1321 | <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> | |
1275 | 1324 | <child internal-child="vbox"> |
1276 | 1325 | <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> | |
1282 | 1331 | <property name="orientation">vertical</property> |
1283 | 1332 | <property name="spacing">6</property> |
1284 | 1333 | <child internal-child="action_area"> |
1285 | 1334 | <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> | |
1288 | 1337 | <child> |
1289 | 1338 | <object class="GtkButton" id="name_dialog_cancel_button"> |
1290 | 1339 | <property name="label">gtk-cancel</property> |
1291 | 1340 | <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> | |
1295 | 1344 | </object> |
1296 | 1345 | <packing> |
1297 | 1346 | <property name="expand">False</property> |
1303 | 1352 | <object class="GtkButton" id="name_dialog_accept_button"> |
1304 | 1353 | <property name="label">gtk-ok</property> |
1305 | 1354 | <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> | |
1311 | 1360 | </object> |
1312 | 1361 | <packing> |
1313 | 1362 | <property name="expand">False</property> |
1325 | 1374 | <child> |
1326 | 1375 | <object class="GtkBox"> |
1327 | 1376 | <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> | |
1330 | 1379 | <property name="spacing">6</property> |
1331 | 1380 | <child> |
1332 | 1381 | <object class="GtkLabel"> |
1333 | 1382 | <property name="visible">True</property> |
1334 | <property name="can_focus">False</property> | |
1383 | <property name="can-focus">False</property> | |
1335 | 1384 | <property name="label" translatable="yes">Name</property> |
1336 | 1385 | </object> |
1337 | 1386 | <packing> |
1343 | 1392 | <child> |
1344 | 1393 | <object class="GtkEntry" id="name_dialog_entry"> |
1345 | 1394 | <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> | |
1348 | 1397 | <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> | |
1352 | 1401 | </object> |
1353 | 1402 | <packing> |
1354 | 1403 | <property name="expand">False</property> |
1367 | 1416 | </child> |
1368 | 1417 | </object> |
1369 | 1418 | <object class="GtkDialog" id="progress_dialog"> |
1370 | <property name="can_focus">False</property> | |
1419 | <property name="can-focus">False</property> | |
1371 | 1420 | <property name="resizable">False</property> |
1372 | 1421 | <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> | |
1378 | 1424 | <child internal-child="vbox"> |
1379 | 1425 | <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> | |
1385 | 1431 | <property name="orientation">vertical</property> |
1386 | 1432 | <property name="spacing">6</property> |
1387 | 1433 | <child internal-child="action_area"> |
1388 | 1434 | <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> | |
1391 | 1437 | <child> |
1392 | 1438 | <object class="GtkButton" id="progress_dialog_cancel_button"> |
1393 | 1439 | <property name="label">gtk-cancel</property> |
1394 | 1440 | <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> | |
1398 | 1444 | </object> |
1399 | 1445 | <packing> |
1400 | 1446 | <property name="expand">True</property> |
1412 | 1458 | <child> |
1413 | 1459 | <object class="GtkBox"> |
1414 | 1460 | <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> | |
1417 | 1463 | <property name="orientation">vertical</property> |
1418 | 1464 | <property name="spacing">6</property> |
1419 | 1465 | <child> |
1420 | 1466 | <object class="GtkLabel" id="progress_label"> |
1421 | 1467 | <property name="visible">True</property> |
1422 | <property name="can_focus">False</property> | |
1468 | <property name="can-focus">False</property> | |
1423 | 1469 | <property name="halign">start</property> |
1424 | 1470 | </object> |
1425 | 1471 | <packing> |
1431 | 1477 | <child> |
1432 | 1478 | <object class="GtkProgressBar" id="progress_bar"> |
1433 | 1479 | <property name="visible">True</property> |
1434 | <property name="can_focus">False</property> | |
1480 | <property name="can-focus">False</property> | |
1435 | 1481 | </object> |
1436 | 1482 | <packing> |
1437 | 1483 | <property name="expand">False</property> |
0 | 0 | PKG_CONFIG ?= pkg-config |
1 | 1 | |
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 | |
5 | 4 | |
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 | |
6 | 13 | 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 | |
9 | 18 | |
10 | 19 | SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ |
11 | 20 | SNDFILE_LIBS = @SNDFILE_LIBS@ |
19 | 19 | |
20 | 20 | #include "../config.h" |
21 | 21 | #include "audio.h" |
22 | #include "utils.h" | |
23 | 22 | |
24 | 23 | #define PA_BUFFER_LEN 4800 |
25 | 24 | #define CHANNELS 1 |
46 | 45 | gshort *v; |
47 | 46 | gint i; |
48 | 47 | |
49 | //XXX: Until a better solution is found this corks the stream without using neither drain nor empty buffers (CPU) | |
50 | 48 | if (audio->release_frames > PA_BUFFER_LEN) |
51 | 49 | { |
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; | |
57 | 55 | debug_print (2, "Writing %2d frames...\n", req_frames); |
58 | 56 | pa_stream_begin_write (stream, &buffer, &size); |
59 | 57 | |
60 | g_mutex_lock (&audio->mutex); | |
58 | g_mutex_lock (&audio->control.mutex); | |
61 | 59 | |
62 | 60 | if (!audio->sample->len) |
63 | 61 | { |
64 | g_mutex_unlock (&audio->mutex); | |
62 | g_mutex_unlock (&audio->control.mutex); | |
65 | 63 | pa_stream_cancel_write (stream); |
66 | 64 | debug_print (2, "Canceled\n"); |
67 | 65 | return; |
68 | 66 | } |
69 | 67 | |
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); | |
73 | 71 | memset (buffer, 0, size); |
74 | 72 | pa_stream_write (stream, buffer, size, NULL, 0, PA_SEEK_RELATIVE); |
75 | 73 | audio->release_frames += req_frames; |
79 | 77 | v = buffer; |
80 | 78 | for (i = 0; i < req_frames; i++) |
81 | 79 | { |
82 | if (audio->pos < audio->sample->len) | |
80 | if (audio->pos < audio->sample->len >> 1) | |
83 | 81 | { |
84 | 82 | *v = ((short *) audio->sample->data)[audio->pos]; |
85 | 83 | audio->pos++; |
99 | 97 | v++; |
100 | 98 | } |
101 | 99 | |
102 | g_mutex_unlock (&audio->mutex); | |
100 | g_mutex_unlock (&audio->control.mutex); | |
103 | 101 | |
104 | 102 | pa_stream_write (stream, buffer, i * 2, NULL, 0, PA_SEEK_RELATIVE); |
105 | 103 | } |
116 | 114 | |
117 | 115 | debug_print (1, "Stopping audio...\n"); |
118 | 116 | |
117 | pa_threaded_mainloop_lock (audio->mainloop); | |
119 | 118 | if (flush) |
120 | 119 | { |
121 | 120 | operation = pa_stream_flush (audio->stream, NULL, NULL); |
130 | 129 | { |
131 | 130 | pa_operation_unref (operation); |
132 | 131 | } |
132 | pa_threaded_mainloop_unlock (audio->mainloop); | |
133 | 133 | } |
134 | 134 | |
135 | 135 | void |
146 | 146 | |
147 | 147 | debug_print (1, "Playing audio...\n"); |
148 | 148 | |
149 | g_mutex_lock (&audio->mutex); | |
149 | g_mutex_lock (&audio->control.mutex); | |
150 | 150 | audio->pos = 0; |
151 | 151 | 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); | |
154 | 155 | operation = pa_stream_cork (audio->stream, 0, NULL, NULL); |
155 | 156 | if (operation != NULL) |
156 | 157 | { |
157 | 158 | pa_operation_unref (operation); |
158 | 159 | } |
160 | pa_threaded_mainloop_unlock (audio->mainloop); | |
159 | 161 | } |
160 | 162 | |
161 | 163 | static void |
167 | 169 | if (info && pa_cvolume_valid (&info->volume)) |
168 | 170 | { |
169 | 171 | 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); | |
171 | 173 | } |
172 | 174 | } |
173 | 175 | |
246 | 248 | } |
247 | 249 | |
248 | 250 | 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)) | |
250 | 253 | { |
251 | 254 | pa_mainloop_api *api; |
252 | 255 | gint err = 0; |
253 | 256 | |
254 | 257 | debug_print (1, "Initializing audio...\n"); |
255 | 258 | |
256 | audio->sample = g_array_new (FALSE, FALSE, sizeof (gshort)); | |
259 | audio->sample = g_byte_array_new (); | |
260 | audio->frames = 0; | |
257 | 261 | 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); | |
260 | 264 | audio->context = pa_context_new (api, PACKAGE); |
261 | 265 | audio->stream = NULL; |
262 | 266 | 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; | |
264 | 271 | |
265 | 272 | if (pa_context_connect (audio->context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) |
266 | 273 | { |
267 | 274 | pa_context_unref (audio->context); |
268 | pa_glib_mainloop_free (audio->mainloop); | |
275 | pa_threaded_mainloop_free (audio->mainloop); | |
269 | 276 | audio->mainloop = NULL; |
270 | 277 | err = -1; |
271 | 278 | } |
273 | 280 | { |
274 | 281 | pa_context_set_state_callback (audio->context, audio_context_callback, |
275 | 282 | audio); |
283 | pa_threaded_mainloop_start (audio->mainloop); | |
284 | ||
285 | ||
276 | 286 | } |
277 | 287 | |
278 | 288 | return err; |
284 | 294 | debug_print (1, "Destroying audio...\n"); |
285 | 295 | |
286 | 296 | audio_stop (audio, TRUE); |
287 | g_array_free (audio->sample, TRUE); | |
297 | ||
298 | g_byte_array_free (audio->sample, TRUE); | |
288 | 299 | if (audio->stream) |
289 | 300 | { |
290 | 301 | pa_stream_unref (audio->stream); |
294 | 305 | if (audio->mainloop) |
295 | 306 | { |
296 | 307 | 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); | |
298 | 310 | audio->mainloop = NULL; |
299 | 311 | } |
312 | ||
313 | g_free (audio->name); | |
300 | 314 | } |
301 | 315 | |
302 | 316 | gboolean |
308 | 322 | void |
309 | 323 | audio_reset_sample (struct audio *audio) |
310 | 324 | { |
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; | |
313 | 328 | audio->pos = 0; |
314 | g_mutex_unlock (&audio->mutex); | |
329 | g_mutex_unlock (&audio->control.mutex); | |
315 | 330 | } |
316 | 331 | |
317 | 332 | void |
19 | 19 | |
20 | 20 | #include <glib.h> |
21 | 21 | #include <pulse/pulseaudio.h> |
22 | #include <pulse/glib-mainloop.h> | |
22 | #include "utils.h" | |
23 | 23 | |
24 | 24 | struct audio |
25 | 25 | { |
26 | GArray *sample; | |
27 | gint frames; | |
26 | GByteArray *sample; | |
27 | guint frames; | |
28 | 28 | gboolean loop; |
29 | pa_glib_mainloop *mainloop; | |
29 | pa_threaded_mainloop *mainloop; | |
30 | 30 | pa_context *context; |
31 | 31 | pa_stream *stream; |
32 | 32 | gint pos; |
33 | 33 | pa_cvolume volume; |
34 | 34 | uint32_t index; |
35 | void (*set_volume_gui_callback) (gdouble); | |
35 | void (*volume_change_callback) (gdouble); | |
36 | 36 | gint release_frames; |
37 | GMutex mutex; | |
38 | gboolean load_active; | |
37 | struct job_control control; | |
38 | gchar *name; | |
39 | 39 | }; |
40 | 40 | |
41 | 41 | void audio_play (struct audio *); |
44 | 44 | |
45 | 45 | gboolean audio_check (struct audio *); |
46 | 46 | |
47 | gint audio_init (struct audio *, void (*)(gdouble)); | |
47 | gint audio_init (struct audio *, void (*)(gdouble), void (*)(gdouble)); | |
48 | 48 | |
49 | 49 | void audio_destroy (struct audio *); |
50 | 50 |
18 | 18 | */ |
19 | 19 | |
20 | 20 | #include "browser.h" |
21 | #include "utils.h" | |
22 | 21 | |
23 | 22 | 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; | |
27 | 28 | 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); | |
53 | 36 | } |
54 | 37 | else |
55 | 38 | { |
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); | |
91 | 44 | |
92 | 45 | return ret; |
93 | 46 | } |
94 | 47 | |
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; | |
114 | 78 | } |
115 | 79 | |
116 | 80 | void |
149 | 113 | browser_refresh (GtkWidget * object, gpointer data) |
150 | 114 | { |
151 | 115 | struct browser *browser = data; |
152 | g_idle_add (browser->load_dir, NULL); | |
116 | g_idle_add (browser_load_dir, browser); | |
153 | 117 | } |
154 | 118 | |
155 | 119 | void |
165 | 129 | new_path = dirname (dup); |
166 | 130 | strcpy (browser->dir, new_path); |
167 | 131 | 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); | |
171 | 139 | } |
172 | 140 | |
173 | 141 | void |
174 | 142 | browser_item_activated (GtkTreeView * view, GtkTreePath * path, |
175 | 143 | GtkTreeViewColumn * column, gpointer data) |
176 | 144 | { |
177 | gchar *icon; | |
178 | gchar *name; | |
179 | 145 | GtkTreeIter iter; |
146 | struct item *item; | |
180 | 147 | struct browser *browser = data; |
181 | 148 | GtkTreeModel *model = GTK_TREE_MODEL (gtk_tree_view_get_model |
182 | 149 | (browser->view)); |
183 | 150 | |
184 | 151 | 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) | |
188 | 155 | { |
189 | 156 | if (strcmp (browser->dir, "/") != 0) |
190 | 157 | { |
191 | 158 | strcat (browser->dir, "/"); |
192 | 159 | } |
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); | |
199 | 169 | } |
200 | 170 | |
201 | 171 | gint |
205 | 175 | gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->view)); |
206 | 176 | return gtk_tree_selection_count_selected_rows (selection); |
207 | 177 | } |
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 | } |
19 | 19 | |
20 | 20 | #include <gtk/gtk.h> |
21 | 21 | #include <libgen.h> |
22 | #include "utils.h" | |
22 | 23 | |
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 | }; | |
27 | 44 | |
28 | 45 | struct browser |
29 | 46 | { |
30 | gint (*mkdir) (const gchar *); | |
31 | gint (*rename) (const gchar *, const gchar *); | |
32 | gint (*delete) (const gchar *, const gchar); | |
33 | GSourceFunc load_dir; | |
34 | 47 | GSourceFunc check_selection; |
35 | 48 | GtkTreeView *view; |
36 | 49 | GtkWidget *up_button; |
43 | 56 | GtkTreePath *dnd_motion_path; |
44 | 57 | gint dnd_timeout_function_id; |
45 | 58 | 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) (); | |
46 | 65 | }; |
47 | 66 | |
48 | gint browser_sort (GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, gpointer); | |
67 | gint browser_sort_samples (GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, | |
68 | gpointer); | |
49 | 69 | |
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 *); | |
52 | 76 | |
53 | 77 | gint browser_get_selected_items_count (struct browser *); |
54 | 78 | |
64 | 88 | |
65 | 89 | void browser_item_activated (GtkTreeView *, GtkTreePath *, |
66 | 90 | 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 |
20 | 20 | #include <stdio.h> |
21 | 21 | #include <math.h> |
22 | 22 | #include <endian.h> |
23 | #include <sys/poll.h> | |
23 | #include <poll.h> | |
24 | 24 | #include <zlib.h> |
25 | 25 | #include <libgen.h> |
26 | #include <json-glib/json-glib.h> | |
26 | 27 | #include "connector.h" |
27 | 28 | #include "utils.h" |
29 | #include "sample.h" | |
30 | #include "package.h" | |
28 | 31 | |
29 | 32 | #define KB 1024 |
30 | 33 | #define BUFF_SIZE (4 * KB) |
31 | 34 | #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 | |
34 | 37 | #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); | |
36 | 195 | |
37 | 196 | static const guint8 MSG_HEADER[] = { 0xf0, 0, 0x20, 0x3c, 0x10, 0 }; |
38 | 197 | |
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[] = | |
50 | 213 | { 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 | |
60 | 260 | }; |
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 | }; | |
73 | 269 | |
74 | 270 | 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 | |
79 | 276 | }; |
80 | 277 | |
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 | ||
81 | 286 | 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 | |
86 | 292 | }; |
87 | 293 | |
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 | ||
88 | 302 | 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 | |
93 | 308 | }; |
94 | 309 | |
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 | ||
95 | 334 | 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 | |
100 | 340 | }; |
101 | 341 | |
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 | |
107 | 348 | }; |
108 | 349 | |
109 | 350 | 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 | |
112 | 355 | }; |
113 | 356 | |
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 | |
116 | 517 | connector_get_msg_status (const GByteArray * msg) |
117 | 518 | { |
118 | 519 | return msg->data[5]; |
119 | 520 | } |
120 | 521 | |
121 | static gchar * | |
522 | static inline gchar * | |
122 | 523 | connector_get_msg_string (const GByteArray * msg) |
123 | 524 | { |
124 | 525 | return (gchar *) & msg->data[6]; |
125 | 526 | } |
126 | 527 | |
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; | |
167 | 543 | return -ENOENT; |
168 | 544 | } |
169 | 545 | else |
170 | 546 | { |
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; | |
194 | 570 | |
195 | 571 | return 0; |
196 | 572 | } |
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); | |
197 | 614 | } |
198 | 615 | |
199 | 616 | static GByteArray * |
254 | 671 | } |
255 | 672 | |
256 | 673 | static GByteArray * |
257 | connector_msg_to_sysex (const GByteArray * msg) | |
674 | connector_msg_to_raw (const GByteArray * msg) | |
258 | 675 | { |
259 | 676 | GByteArray *encoded; |
260 | 677 | GByteArray *sysex = g_byte_array_new (); |
268 | 685 | return sysex; |
269 | 686 | } |
270 | 687 | |
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, | |
273 | 690 | guint * size) |
274 | 691 | { |
275 | if (!connector_get_msg_status (info_msg)) | |
692 | if (connector_get_msg_status (info_msg)) | |
276 | 693 | { |
277 | 694 | if (id) |
278 | 695 | { |
279 | *id = -1; | |
696 | *id = be32toh (*((guint32 *) & info_msg->data[6])); | |
697 | } | |
698 | if (size) | |
699 | { | |
700 | *size = be32toh (*((guint32 *) & info_msg->data[10])); | |
280 | 701 | } |
281 | 702 | } |
282 | 703 | else |
283 | 704 | { |
284 | 705 | if (id) |
285 | 706 | { |
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; | |
293 | 712 | } |
294 | 713 | |
295 | 714 | static GByteArray * |
296 | connector_new_msg_data (const guint8 * data, guint len) | |
715 | connector_new_msg (const guint8 * data, guint len) | |
297 | 716 | { |
298 | 717 | GByteArray *msg = g_byte_array_new (); |
299 | 718 | |
306 | 725 | static GByteArray * |
307 | 726 | connector_new_msg_uint8 (const guint8 * data, guint len, guint8 type) |
308 | 727 | { |
309 | GByteArray *msg = connector_new_msg_data (data, len); | |
728 | GByteArray *msg = connector_new_msg (data, len); | |
310 | 729 | |
311 | 730 | g_byte_array_append (msg, &type, 1); |
312 | 731 | |
316 | 735 | static GByteArray * |
317 | 736 | connector_new_msg_path (const guint8 * data, guint len, const gchar * path) |
318 | 737 | { |
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); | |
323 | 749 | |
324 | 750 | return msg; |
325 | 751 | } |
326 | 752 | |
327 | 753 | 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; | |
332 | 762 | } |
333 | 763 | |
334 | 764 | 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); | |
339 | 772 | } |
340 | 773 | |
341 | 774 | 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); | |
346 | 782 | } |
347 | 783 | |
348 | 784 | 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, | |
353 | 981 | 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); | |
359 | 984 | } |
360 | 985 | |
361 | 986 | 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); | |
374 | 992 | } |
375 | 993 | |
376 | 994 | 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) | |
469 | 996 | { |
470 | 997 | GByteArray *msg; |
471 | 998 | GByteArray *payload; |
494 | 1021 | if (!connector->outputp) |
495 | 1022 | { |
496 | 1023 | error_print ("Output port is NULL\n"); |
497 | return -1; | |
1024 | return -ENOTCONN; | |
498 | 1025 | } |
499 | 1026 | |
500 | 1027 | snd_rawmidi_read (connector->inputp, NULL, 0); // trigger reading |
502 | 1029 | tx_len = snd_rawmidi_write (connector->outputp, data, len); |
503 | 1030 | if (tx_len < 0) |
504 | 1031 | { |
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)); | |
506 | 1034 | connector_destroy (connector); |
507 | return tx_len; | |
508 | 1035 | } |
509 | 1036 | return tx_len; |
510 | 1037 | } |
511 | 1038 | |
512 | ssize_t | |
513 | connector_tx_sysex (struct connector *connector, GByteArray * data, | |
1039 | gint | |
1040 | connector_tx_sysex (struct connector *connector, | |
514 | 1041 | struct connector_sysex_transfer *transfer) |
515 | 1042 | { |
516 | 1043 | ssize_t tx_len; |
517 | 1044 | guint total; |
518 | 1045 | guint len; |
519 | 1046 | guchar *b; |
520 | ssize_t ret = data->len; | |
1047 | gint res = 0; | |
521 | 1048 | |
522 | 1049 | transfer->status = SENDING; |
523 | 1050 | |
524 | b = data->data; | |
1051 | b = transfer->raw->data; | |
525 | 1052 | 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; | |
529 | 1056 | if (len > BUFF_SIZE) |
530 | 1057 | { |
531 | 1058 | len = BUFF_SIZE; |
534 | 1061 | tx_len = connector_tx_raw (connector, b, len); |
535 | 1062 | if (tx_len < 0) |
536 | 1063 | { |
537 | ret = tx_len; | |
538 | errno = EIO; | |
1064 | res = tx_len; | |
539 | 1065 | break; |
540 | 1066 | } |
541 | 1067 | b += len; |
544 | 1070 | |
545 | 1071 | transfer->active = FALSE; |
546 | 1072 | transfer->status = FINISHED; |
547 | return ret; | |
548 | } | |
549 | ||
550 | static ssize_t | |
1073 | return res; | |
1074 | } | |
1075 | ||
1076 | static gint | |
551 | 1077 | connector_tx (struct connector *connector, const GByteArray * msg) |
552 | 1078 | { |
553 | ssize_t ret; | |
554 | uint16_t aux; | |
555 | GByteArray *sysex; | |
1079 | gint res; | |
1080 | guint16 aux; | |
1081 | gchar *text; | |
556 | 1082 | struct connector_sysex_transfer transfer; |
557 | gchar *text; | |
558 | 1083 | |
559 | 1084 | aux = htobe16 (connector->seq); |
560 | memcpy (msg->data, &aux, sizeof (uint16_t)); | |
1085 | memcpy (msg->data, &aux, sizeof (guint16)); | |
561 | 1086 | if (connector->seq == USHRT_MAX) |
562 | 1087 | { |
563 | 1088 | connector->seq = 0; |
568 | 1093 | } |
569 | 1094 | |
570 | 1095 | 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) | |
576 | 1100 | { |
577 | 1101 | if (debug_level > 1) |
578 | 1102 | { |
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); | |
581 | 1106 | free (text); |
582 | 1107 | } |
583 | 1108 | |
586 | 1111 | free (text); |
587 | 1112 | } |
588 | 1113 | |
589 | free_msg (sysex); | |
590 | return ret; | |
1114 | free_msg (transfer.raw); | |
1115 | return res; | |
591 | 1116 | } |
592 | 1117 | |
593 | 1118 | void |
628 | 1153 | if (!connector->inputp) |
629 | 1154 | { |
630 | 1155 | error_print ("Input port is NULL\n"); |
631 | return -1; | |
1156 | return -ENOTCONN; | |
632 | 1157 | } |
633 | 1158 | |
634 | 1159 | total_time = 0; |
669 | 1194 | &revents)) < 0) |
670 | 1195 | { |
671 | 1196 | error_print ("Error while getting poll events. %s.\n", |
672 | g_strerror (errno)); | |
1197 | snd_strerror (err)); | |
673 | 1198 | connector_destroy (connector); |
674 | 1199 | return err; |
675 | 1200 | } |
702 | 1227 | |
703 | 1228 | if (rx_len < 0) |
704 | 1229 | { |
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)); | |
707 | 1232 | connector_destroy (connector); |
708 | 1233 | break; |
709 | 1234 | } |
720 | 1245 | return rx_len; |
721 | 1246 | } |
722 | 1247 | |
723 | GByteArray * | |
1248 | gint | |
724 | 1249 | connector_rx_sysex (struct connector *connector, |
725 | 1250 | struct connector_sysex_transfer *transfer) |
726 | 1251 | { |
727 | 1252 | gint i; |
728 | 1253 | guint8 *b; |
729 | GByteArray *sysex = g_byte_array_new (); | |
1254 | gint res = 0; | |
730 | 1255 | |
731 | 1256 | transfer->status = WAITING; |
1257 | transfer->raw = g_byte_array_new (); | |
732 | 1258 | |
733 | 1259 | i = 0; |
734 | 1260 | if (connector->rx_len < 0) |
747 | 1273 | |
748 | 1274 | if (connector->rx_len == -ENODATA) |
749 | 1275 | { |
750 | errno = ENODATA; | |
1276 | res = -ENODATA; | |
751 | 1277 | goto error; |
752 | 1278 | } |
753 | 1279 | |
754 | 1280 | if (connector->rx_len < 0) |
755 | 1281 | { |
756 | errno = EIO; | |
1282 | res = -EIO; | |
757 | 1283 | goto error; |
758 | 1284 | } |
759 | 1285 | |
773 | 1299 | } |
774 | 1300 | } |
775 | 1301 | |
776 | g_byte_array_append (sysex, b, 1); | |
1302 | g_byte_array_append (transfer->raw, b, 1); | |
777 | 1303 | b++; |
778 | 1304 | i++; |
779 | 1305 | transfer->status = RECEIVING; |
793 | 1319 | |
794 | 1320 | if (connector->rx_len < 0) |
795 | 1321 | { |
796 | errno = EIO; | |
1322 | res = -EIO; | |
797 | 1323 | goto error; |
798 | 1324 | } |
799 | 1325 | |
805 | 1331 | { |
806 | 1332 | if (!connector_is_rt_msg (b, 1)) |
807 | 1333 | { |
808 | g_byte_array_append (sysex, b, 1); | |
1334 | g_byte_array_append (transfer->raw, b, 1); | |
809 | 1335 | } |
810 | 1336 | b++; |
811 | 1337 | i++; |
813 | 1339 | |
814 | 1340 | if (i < connector->rx_len) |
815 | 1341 | { |
816 | g_byte_array_append (sysex, b, 1); | |
1342 | g_byte_array_append (transfer->raw, b, 1); | |
817 | 1343 | connector->rx_len = connector->rx_len - i - 1; |
818 | 1344 | if (connector->rx_len > 0) |
819 | 1345 | { |
828 | 1354 | goto end; |
829 | 1355 | |
830 | 1356 | error: |
831 | free_msg (sysex); | |
832 | sysex = NULL; | |
1357 | free_msg (transfer->raw); | |
1358 | transfer->raw = NULL; | |
833 | 1359 | end: |
834 | 1360 | transfer->active = FALSE; |
835 | 1361 | transfer->status = FINISHED; |
836 | return sysex; | |
1362 | return res; | |
837 | 1363 | } |
838 | 1364 | |
839 | 1365 | static GByteArray * |
840 | 1366 | connector_rx (struct connector *connector) |
841 | 1367 | { |
1368 | gchar *text; | |
842 | 1369 | GByteArray *msg; |
843 | GByteArray *sysex; | |
844 | 1370 | struct connector_sysex_transfer transfer; |
845 | gchar *text; | |
846 | 1371 | |
847 | 1372 | transfer.active = TRUE; |
848 | 1373 | transfer.timeout = SYSEX_TIMEOUT; |
849 | 1374 | transfer.batch = FALSE; |
850 | 1375 | |
851 | sysex = connector_rx_sysex (connector, &transfer); | |
852 | if (!sysex) | |
1376 | if (connector_rx_sysex (connector, &transfer)) | |
853 | 1377 | { |
854 | 1378 | return NULL; |
855 | 1379 | } |
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]))) | |
864 | 1388 | { |
865 | 1389 | if (debug_level > 1) |
866 | 1390 | { |
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); | |
869 | 1394 | free (text); |
870 | 1395 | } |
871 | free_msg (sysex); | |
1396 | free_msg (transfer.raw); | |
872 | 1397 | |
873 | 1398 | transfer.active = TRUE; |
874 | sysex = connector_rx_sysex (connector, &transfer); | |
875 | if (!sysex) | |
1399 | if (connector_rx_sysex (connector, &transfer)) | |
876 | 1400 | { |
877 | 1401 | return NULL; |
878 | 1402 | } |
880 | 1404 | |
881 | 1405 | if (debug_level > 1) |
882 | 1406 | { |
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); | |
885 | 1410 | free (text); |
886 | 1411 | } |
887 | 1412 | |
888 | msg = connector_sysex_to_msg (sysex); | |
1413 | msg = connector_raw_to_msg (transfer.raw); | |
889 | 1414 | if (msg) |
890 | 1415 | { |
891 | 1416 | text = debug_get_hex_msg (msg); |
893 | 1418 | free (text); |
894 | 1419 | } |
895 | 1420 | |
896 | free_msg (sysex); | |
1421 | free_msg (transfer.raw); | |
897 | 1422 | return msg; |
898 | 1423 | } |
899 | 1424 | |
922 | 1447 | return rx_msg; |
923 | 1448 | } |
924 | 1449 | |
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; | |
928 | 1456 | GByteArray *tx_msg; |
929 | 1457 | 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 | ||
942 | 1465 | if (!rx_msg) |
943 | 1466 | { |
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) | |
960 | 1526 | { |
961 | 1527 | gchar *name_copy; |
962 | 1528 | gchar *parent_copy; |
963 | 1529 | gchar *name; |
964 | 1530 | gchar *parent; |
965 | gchar res; | |
966 | struct connector_dir_iterator *d_iter; | |
1531 | enum item_type res; | |
1532 | struct item_iterator iter; | |
967 | 1533 | |
968 | 1534 | if (strcmp (path, "/") == 0) |
969 | 1535 | { |
974 | 1540 | parent_copy = strdup (path); |
975 | 1541 | name = basename (name_copy); |
976 | 1542 | parent = dirname (parent_copy); |
977 | d_iter = connector_read_dir (connector, parent); | |
978 | 1543 | 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) | |
984 | 1549 | { |
985 | res = d_iter->type; | |
1550 | res = iter.item.type; | |
986 | 1551 | break; |
987 | 1552 | } |
988 | 1553 | } |
989 | connector_free_dir_iterator (d_iter); | |
1554 | free_item_iterator (&iter); | |
990 | 1555 | } |
991 | 1556 | |
992 | 1557 | g_free (name_copy); |
995 | 1560 | } |
996 | 1561 | |
997 | 1562 | 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) | |
1000 | 1566 | { |
1001 | 1567 | gint res; |
1002 | 1568 | 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); | |
1027 | 1591 | |
1028 | 1592 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1029 | 1593 | if (!rx_msg) |
1030 | 1594 | { |
1031 | return -1; | |
1595 | return -EIO; | |
1032 | 1596 | } |
1033 | 1597 | //Response: x, x, x, x, 0xa1, [0 (error), 1 (success)]... |
1034 | 1598 | if (connector_get_msg_status (rx_msg)) |
1037 | 1601 | } |
1038 | 1602 | else |
1039 | 1603 | { |
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)); | |
1043 | 1607 | } |
1044 | 1608 | free_msg (rx_msg); |
1045 | 1609 | |
1046 | 1610 | return res; |
1047 | 1611 | } |
1048 | 1612 | |
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; | |
1054 | 1638 | 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; | |
1058 | 1643 | |
1059 | 1644 | //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); | |
1062 | 1649 | if (type == ELEKTROID_FILE) |
1063 | 1650 | { |
1064 | return connector_rename_file (connector, old, new); | |
1651 | return mv (connector, src, dst); | |
1065 | 1652 | } |
1066 | 1653 | else if (type == ELEKTROID_DIR) |
1067 | 1654 | { |
1068 | res = connector_create_dir (connector, new); | |
1655 | res = mkdir (dst, connector); | |
1069 | 1656 | if (res) |
1070 | 1657 | { |
1071 | 1658 | return res; |
1072 | 1659 | } |
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) | |
1077 | 1663 | { |
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); | |
1083 | 1671 | } |
1084 | connector_free_dir_iterator (d_iter); | |
1672 | free_item_iterator (&iter); | |
1085 | 1673 | } |
1086 | 1674 | if (!res) |
1087 | 1675 | { |
1088 | res = connector_delete_dir (connector, old); | |
1676 | res = rmdir (connector, src); | |
1089 | 1677 | } |
1090 | 1678 | return res; |
1091 | 1679 | } |
1092 | 1680 | else |
1093 | 1681 | { |
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) | |
1102 | 1689 | { |
1103 | 1690 | gint res; |
1104 | 1691 | GByteArray *rx_msg; |
1105 | 1692 | 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 | } | |
1117 | 1699 | |
1118 | 1700 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1119 | 1701 | if (!rx_msg) |
1120 | 1702 | { |
1121 | return -1; | |
1703 | return -EIO; | |
1122 | 1704 | } |
1123 | 1705 | //Response: x, x, x, x, 0xX0, [0 (error), 1 (success)]... |
1124 | 1706 | if (connector_get_msg_status (rx_msg)) |
1127 | 1709 | } |
1128 | 1710 | else |
1129 | 1711 | { |
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)); | |
1133 | 1715 | } |
1134 | 1716 | free_msg (rx_msg); |
1135 | 1717 | |
1136 | 1718 | return res; |
1137 | 1719 | } |
1138 | 1720 | |
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; | |
1158 | 1860 | GByteArray *tx_msg; |
1159 | 1861 | GByteArray *rx_msg; |
1160 | ssize_t transferred; | |
1161 | gshort *data; | |
1162 | gint id; | |
1862 | guint transferred; | |
1863 | guint32 id; | |
1163 | 1864 | int i; |
1164 | 1865 | 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 | ||
1179 | 1877 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1180 | 1878 | if (!rx_msg) |
1181 | 1879 | { |
1182 | return -1; | |
1880 | return -EIO; | |
1183 | 1881 | } |
1184 | 1882 | |
1185 | 1883 | //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 | } | |
1187 | 1892 | 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 | ||
1195 | 1894 | transferred = 0; |
1196 | 1895 | 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); | |
1210 | 1910 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1211 | 1911 | if (!rx_msg) |
1212 | 1912 | { |
1213 | return -1; | |
1913 | return -EIO; | |
1214 | 1914 | } |
1215 | 1915 | //Response: x, x, x, x, 0xc2, [0 (error), 1 (success)]... |
1216 | 1916 | if (!connector_get_msg_status (rx_msg)) |
1219 | 1919 | } |
1220 | 1920 | free_msg (rx_msg); |
1221 | 1921 | 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 | } | |
1225 | 1931 | |
1226 | 1932 | usleep (REST_TIME); |
1227 | 1933 | } |
1228 | 1934 | |
1229 | debug_print (2, "%zu frames sent\n", transferred); | |
1935 | debug_print (2, "%d bytes sent\n", transferred); | |
1230 | 1936 | |
1231 | 1937 | if (active) |
1232 | 1938 | { |
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); | |
1239 | 1940 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1240 | 1941 | if (!rx_msg) |
1241 | 1942 | { |
1242 | return -1; | |
1943 | return -EIO; | |
1243 | 1944 | } |
1244 | 1945 | //Response: x, x, x, x, 0xc1, [0 (error), 1 (success)]... |
1245 | 1946 | if (!connector_get_msg_status (rx_msg)) |
1249 | 1950 | free_msg (rx_msg); |
1250 | 1951 | } |
1251 | 1952 | |
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; | |
1260 | 2034 | GByteArray *tx_msg; |
1261 | 2035 | GByteArray *rx_msg; |
1262 | GByteArray *data; | |
1263 | gint id; | |
2036 | GByteArray *array; | |
2037 | guint32 id; | |
1264 | 2038 | guint frames; |
1265 | 2039 | guint next_block_start; |
1266 | 2040 | guint req_size; |
1267 | int offset; | |
1268 | int16_t v; | |
1269 | int16_t *frame; | |
1270 | int i; | |
2041 | guint offset; | |
1271 | 2042 | 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 | ||
1283 | 2051 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1284 | 2052 | if (!rx_msg) |
1285 | 2053 | { |
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 | } | |
1289 | 2064 | free_msg (rx_msg); |
1290 | if (id < 0) | |
1291 | { | |
1292 | error_print ("File %s not found\n", path); | |
1293 | return NULL; | |
1294 | } | |
1295 | 2065 | |
1296 | 2066 | debug_print (2, "%d frames to download\n", frames); |
1297 | 2067 | |
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; | |
1300 | 2081 | 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; | |
1305 | 2084 | while (next_block_start < frames && active) |
1306 | 2085 | { |
1307 | if (progress) | |
1308 | { | |
1309 | progress (next_block_start / (double) frames); | |
1310 | } | |
1311 | ||
1312 | 2086 | req_size = |
1313 | 2087 | frames - next_block_start > |
1314 | TRANSF_BLOCK_SIZE_SAMPLE ? TRANSF_BLOCK_SIZE_SAMPLE : frames - | |
2088 | DATA_TRANSF_BLOCK_BYTES ? DATA_TRANSF_BLOCK_BYTES : frames - | |
1315 | 2089 | 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); | |
1318 | 2091 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1319 | 2092 | if (!rx_msg) |
1320 | 2093 | { |
1321 | result = NULL; | |
2094 | res = -EIO; | |
1322 | 2095 | goto cleanup; |
1323 | 2096 | } |
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], | |
1325 | 2098 | 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 | ||
1326 | 2116 | free_msg (rx_msg); |
1327 | 2117 | |
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 | } | |
1333 | 2126 | |
1334 | 2127 | usleep (REST_TIME); |
1335 | 2128 | } |
1338 | 2131 | |
1339 | 2132 | if (active) |
1340 | 2133 | { |
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); | |
1354 | 2135 | } |
1355 | 2136 | else |
1356 | 2137 | { |
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); | |
1361 | 2142 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1362 | 2143 | if (!rx_msg) |
1363 | 2144 | { |
1364 | if (result) | |
1365 | { | |
1366 | g_array_free (result, TRUE); | |
1367 | result = NULL; | |
1368 | } | |
2145 | res = -EIO; | |
1369 | 2146 | goto cleanup; |
1370 | 2147 | } |
1371 | 2148 | //Response: x, x, x, x, 0xb1, 00 00 00 0a 00 01 65 de (sample id and received bytes) |
1372 | 2149 | free_msg (rx_msg); |
1373 | 2150 | |
1374 | 2151 | 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 | } | |
1414 | 2157 | 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)); | |
1415 | 2212 | } |
1416 | 2213 | |
1417 | 2214 | static GByteArray * |
1418 | 2215 | connector_new_msg_upgrade_os_start (guint size) |
1419 | 2216 | { |
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)); | |
1424 | 2221 | |
1425 | 2222 | return msg; |
1426 | 2223 | } |
1428 | 2225 | static GByteArray * |
1429 | 2226 | connector_new_msg_upgrade_os_write (GByteArray * os_data, gint * offset) |
1430 | 2227 | { |
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)); | |
1433 | 2230 | 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; | |
1440 | 2237 | } |
1441 | 2238 | else |
1442 | 2239 | { |
1448 | 2245 | debug_print (2, "CRC: %0x\n", crc); |
1449 | 2246 | |
1450 | 2247 | aux32 = htobe32 (crc); |
1451 | memcpy (&msg->data[5], &aux32, sizeof (uint32_t)); | |
2248 | memcpy (&msg->data[5], &aux32, sizeof (guint32)); | |
1452 | 2249 | aux32 = htobe32 (len); |
1453 | memcpy (&msg->data[9], &aux32, sizeof (uint32_t)); | |
2250 | memcpy (&msg->data[9], &aux32, sizeof (guint32)); | |
1454 | 2251 | aux32 = htobe32 (*offset); |
1455 | memcpy (&msg->data[13], &aux32, sizeof (uint32_t)); | |
2252 | memcpy (&msg->data[13], &aux32, sizeof (guint32)); | |
1456 | 2253 | |
1457 | 2254 | g_byte_array_append (msg, &os_data->data[*offset], len); |
1458 | 2255 | |
1462 | 2259 | } |
1463 | 2260 | |
1464 | 2261 | gint |
1465 | connector_upgrade_os (struct connector *connector, GByteArray * data, | |
2262 | connector_upgrade_os (struct connector *connector, | |
1466 | 2263 | struct connector_sysex_transfer *transfer) |
1467 | 2264 | { |
1468 | 2265 | GByteArray *tx_msg; |
1473 | 2270 | |
1474 | 2271 | transfer->status = SENDING; |
1475 | 2272 | |
1476 | tx_msg = connector_new_msg_upgrade_os_start (data->len); | |
2273 | tx_msg = connector_new_msg_upgrade_os_start (transfer->raw->len); | |
1477 | 2274 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1478 | 2275 | |
1479 | 2276 | if (!rx_msg) |
1480 | 2277 | { |
1481 | res = -1; | |
2278 | res = -EIO; | |
1482 | 2279 | goto end; |
1483 | 2280 | } |
1484 | 2281 | //Response: x, x, x, x, 0xd1, [0 (ok), 1 (error)]... |
1485 | 2282 | op = connector_get_msg_status (rx_msg); |
1486 | 2283 | if (op) |
1487 | 2284 | { |
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), | |
1491 | 2287 | connector_get_msg_string (rx_msg)); |
1492 | 2288 | free_msg (rx_msg); |
1493 | 2289 | goto end; |
1496 | 2292 | free_msg (rx_msg); |
1497 | 2293 | |
1498 | 2294 | 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); | |
1502 | 2298 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1503 | 2299 | |
1504 | 2300 | if (!rx_msg) |
1505 | 2301 | { |
1506 | res = -1; | |
2302 | res = -EIO; | |
1507 | 2303 | break; |
1508 | 2304 | } |
1509 | 2305 | //Response: x, x, x, x, 0xd1, int32, [0..3]... |
1514 | 2310 | } |
1515 | 2311 | else if (op > 1) |
1516 | 2312 | { |
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), | |
1520 | 2315 | connector_get_msg_string (rx_msg)); |
1521 | 2316 | free_msg (rx_msg); |
1522 | 2317 | break; |
1546 | 2341 | if (err) |
1547 | 2342 | { |
1548 | 2343 | error_print ("Error while closing MIDI port: %s\n", |
1549 | g_strerror (errno)); | |
2344 | snd_strerror (err)); | |
1550 | 2345 | } |
1551 | 2346 | connector->inputp = NULL; |
1552 | 2347 | } |
1557 | 2352 | if (err) |
1558 | 2353 | { |
1559 | 2354 | error_print ("Error while closing MIDI port: %s\n", |
1560 | g_strerror (errno)); | |
2355 | snd_strerror (err)); | |
1561 | 2356 | } |
1562 | 2357 | connector->outputp = NULL; |
1563 | 2358 | } |
1565 | 2360 | if (connector->device_name) |
1566 | 2361 | { |
1567 | 2362 | free (connector->device_name); |
2363 | free (connector->fw_version); | |
2364 | free (connector->alias); | |
1568 | 2365 | connector->device_name = NULL; |
1569 | 2366 | } |
1570 | 2367 | |
1579 | 2376 | free (connector->pfds); |
1580 | 2377 | connector->pfds = NULL; |
1581 | 2378 | } |
2379 | ||
2380 | if (connector->dir_cache) | |
2381 | { | |
2382 | g_hash_table_destroy (connector->dir_cache); | |
2383 | connector->dir_cache = NULL; | |
2384 | } | |
1582 | 2385 | } |
1583 | 2386 | |
1584 | 2387 | 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) | |
1587 | 2391 | { |
1588 | 2392 | GByteArray *tx_msg; |
1589 | 2393 | GByteArray *rx_msg; |
1590 | 2394 | gint8 op; |
1591 | uint64_t *data; | |
2395 | guint64 *data; | |
2396 | int index; | |
1592 | 2397 | gint res = 0; |
1593 | 2398 | |
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); | |
1596 | 2401 | rx_msg = connector_tx_and_rx (connector, tx_msg); |
1597 | ||
1598 | 2402 | if (!rx_msg) |
1599 | 2403 | { |
1600 | return -1; | |
2404 | return -EIO; | |
1601 | 2405 | } |
1602 | 2406 | |
1603 | 2407 | op = connector_get_msg_status (rx_msg); |
1604 | 2408 | if (!op) |
1605 | 2409 | { |
1606 | errno = EIO; | |
1607 | error_print ("%s (%s)\n", g_strerror (errno), | |
2410 | error_print ("%s (%s)\n", snd_strerror (-EIO), | |
1608 | 2411 | connector_get_msg_string (rx_msg)); |
1609 | 2412 | 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]; | |
1615 | 2428 | statfs->bfree = be64toh (*data); |
1616 | data = (uint64_t *) & rx_msg->data[14]; | |
2429 | data = (guint64 *) & rx_msg->data[14]; | |
1617 | 2430 | statfs->bsize = be64toh (*data); |
1618 | 2431 | |
1619 | 2432 | free_msg (rx_msg); |
1621 | 2434 | return res; |
1622 | 2435 | } |
1623 | 2436 | |
1624 | float | |
1625 | connector_statfs_use_percent (struct connector_statfs *statfs) | |
2437 | gdouble | |
2438 | connector_get_storage_stats_percent (struct connector_storage_stats *statfs) | |
1626 | 2439 | { |
1627 | 2440 | return (statfs->bsize - statfs->bfree) * 100.0 / statfs->bsize; |
1628 | 2441 | } |
1641 | 2454 | return CONNECTOR_DEVICE_DESCS[i]; |
1642 | 2455 | } |
1643 | 2456 | } |
1644 | return &NULL_DEVICE_DESC; | |
2457 | return NULL; | |
1645 | 2458 | } |
1646 | 2459 | |
1647 | 2460 | gint |
1649 | 2462 | { |
1650 | 2463 | int err; |
1651 | 2464 | GByteArray *tx_msg; |
1652 | GByteArray *rx_msg_device; | |
1653 | GByteArray *rx_msg_fw_ver; | |
1654 | GByteArray *rx_msg_uid; | |
2465 | GByteArray *rx_msg; | |
1655 | 2466 | snd_rawmidi_params_t *params; |
1656 | 2467 | gchar name[32]; |
1657 | 2468 | sprintf (name, "hw:%d", card); |
1661 | 2472 | connector->buffer = NULL; |
1662 | 2473 | connector->rx_len = 0; |
1663 | 2474 | connector->pfds = NULL; |
2475 | connector->dir_cache = NULL; | |
1664 | 2476 | if (card < 0) |
1665 | 2477 | { |
1666 | 2478 | debug_print (1, "Invalid card\n"); |
1673 | 2485 | snd_rawmidi_open (&connector->inputp, &connector->outputp, |
1674 | 2486 | name, SND_RAWMIDI_NONBLOCK | SND_RAWMIDI_SYNC)) < 0) |
1675 | 2487 | { |
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)); | |
1677 | 2489 | goto cleanup; |
1678 | 2490 | } |
1679 | 2491 | |
1742 | 2554 | goto cleanup_params; |
1743 | 2555 | } |
1744 | 2556 | |
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); | |
1760 | 2584 | |
1761 | 2585 | if (debug_level > 1) |
1762 | 2586 | { |
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 | } | |
1773 | 2596 | |
1774 | 2597 | 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); | |
1778 | 2600 | debug_print (1, "Connected to %s\n", connector->device_name); |
1779 | 2601 | err = 0; |
1780 | free_msg (rx_msg_fw_ver); | |
1781 | cleanup_device: | |
1782 | free_msg (rx_msg_device); | |
2602 | ||
1783 | 2603 | cleanup_params: |
1784 | 2604 | snd_rawmidi_params_free (params); |
1785 | 2605 | cleanup: |
1889 | 2709 | return; |
1890 | 2710 | } |
1891 | 2711 | 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) | |
1894 | 2713 | { |
1895 | 2714 | connector_system_device = |
1896 | 2715 | connector_get_system_device (ctl, card, device); |
1915 | 2734 | g_array_new (FALSE, FALSE, sizeof (struct connector_system_device)); |
1916 | 2735 | |
1917 | 2736 | card = -1; |
1918 | while (((err = snd_card_next (&card)) == 0) && (card >= 0)) | |
2737 | while (!(err = snd_card_next (&card)) && card >= 0) | |
1919 | 2738 | { |
1920 | 2739 | connector_fill_card_elektron_devices (card, devices); |
1921 | 2740 | } |
1926 | 2745 | |
1927 | 2746 | return devices; |
1928 | 2747 | } |
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 | } |
19 | 19 | |
20 | 20 | #include <glib.h> |
21 | 21 | #include <alsa/asoundlib.h> |
22 | #include "utils.h" | |
23 | ||
24 | #ifndef CONNECTOR_H | |
25 | #define CONNECTOR_H | |
22 | 26 | |
23 | 27 | #define SYSEX_TIMEOUT 5000 |
24 | ||
25 | #define CAP_SAMPLE 0b00000001 | |
28 | #define REST_TIME 50000 | |
26 | 29 | |
27 | 30 | struct connector_device_desc |
28 | 31 | { |
32 | const gchar *name; | |
33 | const gchar *alias; | |
29 | 34 | guint8 id; |
30 | gchar *model; | |
31 | guint8 capabilities; | |
32 | guint8 startup_mode; | |
35 | guint8 fss; | |
36 | guint8 storages; | |
33 | 37 | }; |
34 | 38 | |
35 | 39 | struct connector |
38 | 42 | snd_rawmidi_t *inputp; |
39 | 43 | snd_rawmidi_t *outputp; |
40 | 44 | gchar *device_name; |
45 | gchar *alias; | |
46 | gchar *fw_version; | |
41 | 47 | gushort seq; |
42 | 48 | GMutex mutex; |
43 | 49 | ssize_t rx_len; |
44 | 50 | guint8 *buffer; |
45 | 51 | gint npfds; |
46 | 52 | struct pollfd *pfds; |
53 | GHashTable *dir_cache; | |
47 | 54 | }; |
48 | 55 | |
49 | struct connector_dir_iterator | |
56 | enum connector_fs | |
50 | 57 | { |
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 | { | |
55 | 68 | 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; | |
57 | 76 | }; |
58 | 77 | |
59 | 78 | struct connector_system_device |
77 | 96 | gint timeout; //Measured in ms. -1 is infinite. |
78 | 97 | gboolean batch; |
79 | 98 | GMutex mutex; |
99 | GByteArray *raw; | |
80 | 100 | }; |
81 | 101 | |
82 | struct connector_sample_transfer | |
102 | enum connector_storage | |
83 | 103 | { |
84 | gboolean active; | |
85 | GMutex mutex; | |
104 | STORAGE_PLUS_DRIVE = 0x1, | |
105 | STORAGE_RAM = 0x2 | |
86 | 106 | }; |
87 | 107 | |
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 | |
96 | 109 | { |
97 | 110 | const gchar *name; |
98 | 111 | guint64 bsize; |
99 | 112 | guint64 bfree; |
100 | 113 | }; |
114 | ||
115 | const struct fs_operations *connector_get_fs_operations (enum connector_fs); | |
101 | 116 | |
102 | 117 | gint connector_init (struct connector *, gint); |
103 | 118 | |
105 | 120 | |
106 | 121 | gboolean connector_check (struct connector *); |
107 | 122 | |
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 | ||
133 | 123 | GArray *connector_get_system_devices (); |
134 | 124 | |
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 *); | |
137 | 127 | |
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 *); | |
141 | 130 | |
142 | 131 | void connector_rx_drain (struct connector *); |
143 | 132 | |
144 | gint connector_upgrade_os (struct connector *, GByteArray *, | |
133 | gint connector_upgrade_os (struct connector *, | |
145 | 134 | struct connector_sysex_transfer *); |
146 | 135 | |
147 | void free_msg (gpointer); | |
136 | gint connector_get_storage_stats (struct connector *, | |
137 | enum connector_storage, | |
138 | struct connector_storage_stats *); | |
148 | 139 | |
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 | *); | |
151 | 142 | |
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 |
25 | 25 | #include <signal.h> |
26 | 26 | #include <stdint.h> |
27 | 27 | #include <inttypes.h> |
28 | #include <stddef.h> | |
28 | 29 | #include "connector.h" |
29 | #include "sample.h" | |
30 | 30 | #include "utils.h" |
31 | 31 | |
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 | ||
32 | 36 | 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 * | |
36 | 74 | cli_get_path (gchar * device_path) |
37 | 75 | { |
38 | 76 | gint len = strlen (device_path); |
67 | 105 | } |
68 | 106 | |
69 | 107 | static gint |
70 | cli_connect (const char *device_path) | |
108 | cli_connect (const char *device_path, enum connector_fs fs) | |
71 | 109 | { |
72 | 110 | 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; | |
74 | 119 | } |
75 | 120 | |
76 | 121 | 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); | |
82 | 129 | |
83 | 130 | if (optind == argc) |
84 | 131 | { |
90 | 137 | device_path = argv[optind]; |
91 | 138 | } |
92 | 139 | |
93 | res = cli_connect (device_path); | |
94 | ||
95 | if (res < 0) | |
140 | if (cli_connect (device_path, fs)) | |
96 | 141 | { |
97 | 142 | return EXIT_FAILURE; |
98 | 143 | } |
99 | 144 | |
100 | 145 | path = cli_get_path (device_path); |
101 | 146 | |
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); | |
116 | 158 | |
117 | 159 | return EXIT_SUCCESS; |
118 | 160 | } |
119 | 161 | |
120 | 162 | 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; | |
125 | 170 | |
126 | 171 | if (optind == argc) |
127 | 172 | { |
133 | 178 | device_path = argv[optind]; |
134 | 179 | } |
135 | 180 | |
136 | res = cli_connect (device_path); | |
137 | ||
138 | if (res < 0) | |
181 | if (cli_connect (device_path, fs)) | |
139 | 182 | { |
140 | 183 | return EXIT_FAILURE; |
141 | 184 | } |
142 | 185 | |
143 | 186 | path = cli_get_path (device_path); |
144 | 187 | |
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; | |
146 | 192 | } |
147 | 193 | |
148 | 194 | 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; | |
155 | 204 | |
156 | 205 | if (optind == argc) |
157 | 206 | { |
160 | 209 | } |
161 | 210 | else |
162 | 211 | { |
163 | device_path_src = argv[optind]; | |
212 | device_src_path = argv[optind]; | |
164 | 213 | optind++; |
165 | 214 | } |
166 | 215 | |
171 | 220 | } |
172 | 221 | else |
173 | 222 | { |
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) | |
180 | 229 | { |
181 | 230 | error_print ("Source and destination device must be the same\n"); |
182 | 231 | return EXIT_FAILURE; |
183 | 232 | } |
184 | 233 | |
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; | |
350 | 245 | } |
351 | 246 | |
352 | 247 | static int |
353 | 248 | cli_info (int argc, char *argv[], int optind) |
354 | 249 | { |
355 | 250 | gchar *device_path; |
356 | gint res; | |
251 | gchar *comma; | |
357 | 252 | |
358 | 253 | if (optind == argc) |
359 | 254 | { |
365 | 260 | device_path = argv[optind]; |
366 | 261 | } |
367 | 262 | |
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"); | |
376 | 279 | |
377 | 280 | return EXIT_SUCCESS; |
378 | 281 | } |
381 | 284 | cli_df (int argc, char *argv[], int optind) |
382 | 285 | { |
383 | 286 | gchar *device_path; |
287 | gchar *size; | |
288 | gchar *diff; | |
289 | gchar *free; | |
384 | 290 | gint res; |
385 | struct connector_statfs statfs; | |
386 | enum connector_fs_type fs; | |
291 | struct connector_storage_stats statfs; | |
292 | enum connector_storage storage; | |
387 | 293 | |
388 | 294 | if (optind == argc) |
389 | 295 | { |
395 | 301 | device_path = argv[optind]; |
396 | 302 | } |
397 | 303 | |
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", | |
406 | 315 | "Used", "Available", "Use%"); |
407 | 316 | |
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); | |
417 | 556 | } |
418 | 557 | |
419 | 558 | static void |
420 | 559 | cli_end (int sig) |
421 | 560 | { |
422 | sample_transfer.active = FALSE; | |
561 | control.active = FALSE; | |
423 | 562 | } |
424 | 563 | |
425 | 564 | int |
430 | 569 | gchar *command; |
431 | 570 | gint vflg = 0, errflg = 0; |
432 | 571 | struct sigaction action, old_action; |
572 | gint fs; | |
573 | char op[LABEL_MAX]; | |
574 | char type[LABEL_MAX]; | |
433 | 575 | |
434 | 576 | action.sa_handler = cli_end; |
435 | 577 | sigemptyset (&action.sa_mask); |
494 | 636 | exit (EXIT_FAILURE); |
495 | 637 | } |
496 | 638 | |
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); | |
540 | 644 | 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: | |
543 | 760 | if (connector_check (&connector)) |
544 | 761 | { |
545 | 762 | connector_destroy (&connector); |
546 | 763 | } |
764 | ||
765 | usleep (REST_TIME * 2); | |
547 | 766 | return res; |
548 | 767 | } |
19 | 19 | |
20 | 20 | #include "../config.h" |
21 | 21 | #include <limits.h> |
22 | #include <locale.h> | |
22 | 23 | #include <gtk/gtk.h> |
23 | #include <unistd.h> | |
24 | #include "connector.h" | |
25 | #include <sys/stat.h> | |
26 | #include <sys/types.h> | |
27 | 24 | #include <glib-unix.h> |
28 | 25 | #include <glib/gi18n.h> |
29 | 26 | #include <glib/gprintf.h> |
30 | 27 | #define _GNU_SOURCE |
31 | 28 | #include <getopt.h> |
29 | #include "connector.h" | |
32 | 30 | #include "browser.h" |
33 | 31 | #include "audio.h" |
34 | 32 | #include "sample.h" |
35 | 33 | #include "utils.h" |
36 | 34 | #include "notifier.h" |
35 | #include "local.h" | |
36 | #include "preferences.h" | |
37 | 37 | |
38 | 38 | #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 | |
51 | 39 | |
52 | 40 | #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, | |
66 | 79 | }; |
67 | 80 | |
68 | 81 | enum elektroid_task_type |
80 | 93 | CANCELED |
81 | 94 | }; |
82 | 95 | |
83 | struct elektroid_sample_transfer | |
84 | { | |
85 | struct connector_sample_transfer transfer; | |
96 | struct elektroid_transfer | |
97 | { | |
98 | struct job_control control; | |
86 | 99 | 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 | |
88 | 101 | 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 | |
89 | 103 | }; |
90 | 104 | |
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; | |
95 | 109 | }; |
96 | 110 | |
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} | |
103 | 123 | }; |
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 }; | |
104 | 132 | |
105 | 133 | static GtkTargetEntry TARGET_ENTRIES_LOCAL_DST[] = { |
106 | 134 | {TEXT_URI_LIST_ELEKTROID, GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET, |
158 | 186 | |
159 | 187 | static struct audio audio; |
160 | 188 | static struct connector connector; |
161 | static gboolean autoplay; | |
189 | static struct preferences preferences; | |
162 | 190 | |
163 | 191 | static GThread *load_thread = NULL; |
164 | 192 | static GThread *task_thread = NULL; |
165 | 193 | 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; | |
168 | 196 | |
169 | 197 | static GThread *notifier_thread = NULL; |
170 | 198 | struct notifier notifier; |
188 | 216 | static GtkListStore *devices_list_store; |
189 | 217 | static GtkComboBox *devices_combo; |
190 | 218 | static GtkWidget *upload_menuitem; |
219 | static GtkWidget *local_audio_box; | |
191 | 220 | static GtkWidget *local_play_menuitem; |
192 | 221 | static GtkWidget *local_open_menuitem; |
193 | 222 | static GtkWidget *local_show_menuitem; |
204 | 233 | static GtkWidget *cancel_task_button; |
205 | 234 | static GtkWidget *remove_tasks_button; |
206 | 235 | 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 | } | |
207 | 297 | |
208 | 298 | static void |
209 | 299 | show_error_msg (const char *format, ...) |
217 | 307 | dialog = gtk_message_dialog_new (GTK_WINDOW (main_window), |
218 | 308 | GTK_DIALOG_DESTROY_WITH_PARENT | |
219 | 309 | GTK_DIALOG_MODAL, |
220 | GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, msg); | |
310 | GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", | |
311 | msg); | |
221 | 312 | gtk_dialog_run (GTK_DIALOG (dialog)); |
222 | 313 | gtk_widget_destroy (dialog); |
223 | 314 | g_free (msg); |
315 | va_end (args); | |
224 | 316 | } |
225 | 317 | |
226 | 318 | static void |
233 | 325 | |
234 | 326 | debug_print (1, "Loading devices...\n"); |
235 | 327 | |
328 | gtk_list_store_clear (fs_list_store); | |
236 | 329 | gtk_list_store_clear (devices_list_store); |
237 | 330 | |
238 | 331 | for (i = 0; i < devices->len; i++) |
250 | 343 | device_index = auto_select && i == 1 ? 0 : -1; |
251 | 344 | debug_print (1, "Selecting device %d...\n", device_index); |
252 | 345 | 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 | } | |
253 | 359 | } |
254 | 360 | |
255 | 361 | static void |
258 | 364 | gchar *status; |
259 | 365 | gchar *statfss_str; |
260 | 366 | gint res; |
261 | enum connector_fs_type fs; | |
262 | struct connector_statfs statfs; | |
367 | enum connector_storage storage; | |
368 | struct connector_storage_stats statfs; | |
263 | 369 | GString *statfss; |
264 | 370 | |
265 | 371 | gtk_statusbar_pop (status_bar, 0); |
268 | 374 | { |
269 | 375 | statfss = g_string_new (NULL); |
270 | 376 | |
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) | |
274 | 381 | { |
275 | res = connector_statfs (&connector, fs, &statfs); | |
382 | res = | |
383 | connector_get_storage_stats (&connector, storage, &statfs); | |
276 | 384 | if (!res) |
277 | 385 | { |
278 | 386 | g_string_append_printf (statfss, " %s %.2f%%", |
279 | 387 | statfs.name, |
280 | connector_statfs_use_percent | |
388 | connector_get_storage_stats_percent | |
281 | 389 | (&statfs)); |
282 | 390 | } |
283 | 391 | } |
299 | 407 | static gboolean |
300 | 408 | elektroid_get_next_queued_task (GtkTreeIter * iter, |
301 | 409 | enum elektroid_task_type *type, |
302 | gchar ** src, gchar ** dst) | |
410 | gchar ** src, gchar ** dst, gint * fs) | |
303 | 411 | { |
304 | 412 | enum elektroid_task_status status; |
305 | 413 | gboolean found = FALSE; |
314 | 422 | TASK_LIST_STORE_STATUS_FIELD, &status, |
315 | 423 | TASK_LIST_STORE_TYPE_FIELD, type, |
316 | 424 | 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); | |
318 | 427 | } |
319 | 428 | else |
320 | 429 | { |
340 | 449 | GtkListStore *list_store; |
341 | 450 | GtkTreeIter iter; |
342 | 451 | 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); | |
344 | 454 | |
345 | 455 | gtk_widget_set_sensitive (remote_box, connected); |
346 | 456 | gtk_widget_set_sensitive (rx_sysex_button, connected && !queued); |
400 | 510 | elektroid_cancel_running_sysex (GtkDialog * dialog, gint response_id, |
401 | 511 | gpointer data) |
402 | 512 | { |
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); | |
406 | 516 | } |
407 | 517 | |
408 | 518 | static void |
426 | 536 | gboolean active; |
427 | 537 | enum connector_sysex_transfer_status status; |
428 | 538 | |
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); | |
432 | 542 | |
433 | 543 | switch (status) |
434 | 544 | { |
448 | 558 | } |
449 | 559 | gtk_label_set_text (GTK_LABEL (progress_label), text); |
450 | 560 | |
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); | |
454 | 564 | |
455 | 565 | return active; |
456 | 566 | } |
458 | 568 | static gpointer |
459 | 569 | elektroid_rx_sysex_thread (gpointer data) |
460 | 570 | { |
571 | gint *res = malloc (sizeof (gint)); | |
461 | 572 | 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; | |
468 | 578 | |
469 | 579 | g_timeout_add (100, elektroid_update_sysex_progress, NULL); |
470 | 580 | |
471 | 581 | 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); | |
477 | 588 | free (text); |
478 | 589 | } |
479 | 590 | |
480 | 591 | gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_ACCEPT); |
481 | 592 | |
482 | return msg; | |
593 | return res; | |
483 | 594 | } |
484 | 595 | |
485 | 596 | static gboolean |
498 | 609 | GtkWidget *dialog; |
499 | 610 | GtkFileChooser *chooser; |
500 | 611 | GtkFileFilter *filter; |
501 | gint res; | |
612 | gint dres; | |
502 | 613 | gchar *filename; |
503 | 614 | gchar *filename_w_ext; |
504 | 615 | const gchar *ext; |
505 | FILE *file; | |
506 | GByteArray *sysex_data; | |
616 | gint *res; | |
507 | 617 | GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE; |
508 | 618 | |
509 | 619 | g_idle_add (elektroid_start_rx_thread, NULL); |
510 | 620 | |
511 | 621 | 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; | |
514 | 624 | gtk_widget_hide (GTK_WIDGET (progress_dialog)); |
515 | 625 | |
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); | |
524 | 635 | return; |
525 | 636 | } |
526 | 637 | |
527 | if (!sysex_data) | |
638 | if (*res) | |
528 | 639 | { |
529 | 640 | elektroid_check_connector (); |
641 | g_free (res); | |
530 | 642 | return; |
531 | 643 | } |
532 | 644 | |
575 | 687 | |
576 | 688 | if (filename != NULL) |
577 | 689 | { |
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); | |
583 | 698 | g_free (filename); |
584 | 699 | } |
585 | 700 | |
590 | 705 | elektroid_tx_sysex_thread (gpointer data) |
591 | 706 | { |
592 | 707 | 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; | |
597 | 713 | |
598 | 714 | g_timeout_add (100, elektroid_update_sysex_progress, NULL); |
599 | 715 | |
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); | |
606 | 720 | debug_print (1, "SysEx message sent (%d): %s\n", |
607 | sysex_transfer.data->len, text); | |
721 | sysex_transfer.raw->len, text); | |
608 | 722 | free (text); |
609 | 723 | } |
610 | 724 | |
611 | 725 | gtk_dialog_response (GTK_DIALOG (progress_dialog), GTK_RESPONSE_CANCEL); |
612 | 726 | |
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) | |
627 | 732 | { |
628 | 733 | GtkWidget *dialog; |
629 | 734 | GtkFileChooser *chooser; |
630 | 735 | GtkFileFilter *filter; |
631 | gint res; | |
736 | gint res, lres; | |
632 | 737 | char *filename; |
633 | FILE *file; | |
634 | long size; | |
635 | 738 | gint *response; |
636 | 739 | GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; |
637 | 740 | |
655 | 758 | filename = gtk_file_chooser_get_filename (chooser); |
656 | 759 | gtk_widget_destroy (dialog); |
657 | 760 | 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 | ||
682 | 791 | |
683 | 792 | if (*response < 0) |
684 | 793 | { |
696 | 805 | static void |
697 | 806 | elektroid_tx_sysex (GtkWidget * object, gpointer data) |
698 | 807 | { |
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); | |
719 | 809 | } |
720 | 810 | |
721 | 811 | static void |
722 | 812 | elektroid_upgrade_os (GtkWidget * object, gpointer data) |
723 | 813 | { |
724 | elektroid_tx_sysex_common (elektroid_os_upgrade_thread); | |
814 | elektroid_tx_sysex_common (connector_upgrade_os); | |
725 | 815 | connector_destroy (&connector); |
726 | 816 | elektroid_check_connector (); |
727 | 817 | } |
746 | 836 | { |
747 | 837 | gboolean ready_to_play; |
748 | 838 | |
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); | |
753 | 843 | |
754 | 844 | if (ready_to_play) |
755 | 845 | { |
757 | 847 | { |
758 | 848 | elektroid_controls_set_sensitive (TRUE); |
759 | 849 | } |
760 | if (autoplay) | |
850 | if (preferences.autoplay) | |
761 | 851 | { |
762 | 852 | audio_play (&audio); |
763 | 853 | } |
772 | 862 | struct browser *browser) |
773 | 863 | { |
774 | 864 | GtkTreeIter iter; |
775 | gchar *name; | |
776 | gchar *icon; | |
777 | 865 | gchar *path; |
778 | gchar type; | |
866 | gchar *id_path; | |
779 | 867 | gint err; |
868 | struct item *item; | |
780 | 869 | |
781 | 870 | 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) | |
790 | 878 | { |
791 | 879 | show_error_msg (_("Error while deleting “%s”: %s."), |
792 | path, g_strerror (errno)); | |
880 | path, g_strerror (err)); | |
793 | 881 | } |
794 | 882 | else |
795 | 883 | { |
796 | 884 | gtk_list_store_remove (GTK_LIST_STORE (model), &iter); |
797 | 885 | } |
798 | 886 | |
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); | |
802 | 890 | } |
803 | 891 | |
804 | 892 | static void |
805 | 893 | elektroid_delete_files (GtkWidget * object, gpointer data) |
806 | 894 | { |
807 | 895 | GtkTreeRowReference *reference; |
808 | GList *item; | |
896 | GList *list; | |
809 | 897 | GtkTreePath *tree_path; |
810 | 898 | GtkTreeSelection *selection; |
811 | 899 | GtkTreeModel *model; |
837 | 925 | tree_path_list = gtk_tree_selection_get_selected_rows (selection, &model); |
838 | 926 | ref_list = NULL; |
839 | 927 | |
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); | |
843 | 931 | ref_list = g_list_append (ref_list, reference); |
844 | 932 | } |
845 | 933 | g_list_free_full (tree_path_list, (GDestroyNotify) gtk_tree_path_free); |
846 | 934 | |
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); | |
850 | 938 | elektroid_delete_file (model, tree_path, browser); |
851 | 939 | } |
852 | 940 | g_list_free_full (ref_list, (GDestroyNotify) gtk_tree_row_reference_free); |
853 | 941 | |
854 | browser->load_dir (NULL); | |
942 | browser_load_dir (browser); | |
855 | 943 | } |
856 | 944 | |
857 | 945 | static void |
858 | 946 | elektroid_rename_item (GtkWidget * object, gpointer data) |
859 | 947 | { |
860 | char *old_name; | |
861 | 948 | char *old_path; |
862 | 949 | char *new_path; |
863 | 950 | int result; |
864 | 951 | gint err; |
865 | 952 | GtkTreeIter iter; |
953 | struct item *item; | |
866 | 954 | struct browser *browser = data; |
867 | 955 | GtkTreeModel *model = |
868 | 956 | GTK_TREE_MODEL (gtk_tree_view_get_model (browser->view)); |
869 | 957 | |
870 | 958 | 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); | |
876 | 963 | gtk_widget_grab_focus (GTK_WIDGET (name_dialog_entry)); |
877 | 964 | gtk_widget_set_sensitive (name_dialog_accept_button, FALSE); |
878 | 965 | |
890 | 977 | new_path = |
891 | 978 | chain_path (browser->dir, gtk_entry_get_text (name_dialog_entry)); |
892 | 979 | |
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) | |
896 | 983 | { |
897 | 984 | show_error_msg (_("Error while renaming to “%s”: %s."), |
898 | new_path, g_strerror (errno)); | |
985 | new_path, g_strerror (err)); | |
899 | 986 | } |
900 | 987 | else |
901 | 988 | { |
902 | browser->load_dir (NULL); | |
989 | browser_load_dir (browser); | |
903 | 990 | } |
904 | 991 | |
905 | 992 | free (new_path); |
906 | 993 | } |
907 | 994 | } |
908 | 995 | |
909 | free (old_name); | |
910 | free (old_path); | |
996 | browser_free_item (item); | |
997 | g_free (old_path); | |
911 | 998 | gtk_widget_hide (GTK_WIDGET (name_dialog)); |
912 | 999 | } |
913 | 1000 | |
919 | 1006 | GtkTreeSelection *selection; |
920 | 1007 | GtkTreeModel *model; |
921 | 1008 | GList *tree_path_list; |
922 | GList *item; | |
1009 | GList *list; | |
923 | 1010 | gchar *uri; |
924 | gchar *item_name; | |
925 | gchar *full_path; | |
1011 | gchar *path; | |
1012 | struct item *item; | |
926 | 1013 | struct browser *browser = data; |
927 | 1014 | |
928 | 1015 | selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); |
930 | 1017 | tree_path_list = gtk_tree_selection_get_selected_rows (selection, &model); |
931 | 1018 | |
932 | 1019 | 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); | |
939 | 1026 | if (widget == GTK_WIDGET (local_browser.view)) |
940 | 1027 | { |
941 | uri = g_filename_to_uri (full_path, NULL, NULL); | |
1028 | uri = g_filename_to_uri (path, NULL, NULL); | |
942 | 1029 | } |
943 | 1030 | else if (widget == GTK_WIDGET (remote_browser.view)) |
944 | 1031 | { |
945 | uri = chain_path ("file://", &full_path[1]); | |
1032 | uri = chain_path ("file://", &path[1]); | |
946 | 1033 | } |
947 | 1034 | else |
948 | 1035 | { |
949 | 1036 | continue; |
950 | 1037 | } |
951 | g_free (full_path); | |
1038 | g_free (path); | |
952 | 1039 | g_string_append (browser->dnd_data, uri); |
953 | 1040 | g_free (uri); |
954 | 1041 | g_string_append (browser->dnd_data, "\n"); |
1044 | 1131 | if (!path) |
1045 | 1132 | { |
1046 | 1133 | gtk_tree_selection_unselect_all (selection); |
1134 | gtk_menu_popup_at_pointer (browser->menu, (GdkEvent *) event); | |
1047 | 1135 | return FALSE; |
1048 | 1136 | } |
1049 | 1137 | |
1121 | 1209 | static gpointer |
1122 | 1210 | elektroid_load_sample (gpointer path) |
1123 | 1211 | { |
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); | |
1134 | 1229 | |
1135 | 1230 | free (path); |
1136 | 1231 | |
1152 | 1247 | { |
1153 | 1248 | debug_print (1, "Stopping load thread...\n"); |
1154 | 1249 | |
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); | |
1158 | 1253 | |
1159 | 1254 | if (load_thread) |
1160 | 1255 | { |
1179 | 1274 | { |
1180 | 1275 | debug_print (1, "Stopping task thread...\n"); |
1181 | 1276 | |
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); | |
1185 | 1280 | |
1186 | 1281 | elektroid_join_task_thread (); |
1187 | 1282 | } |
1190 | 1285 | elektroid_remote_check_selection (gpointer data) |
1191 | 1286 | { |
1192 | 1287 | 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); | |
1197 | 1295 | |
1198 | 1296 | return FALSE; |
1199 | 1297 | } |
1203 | 1301 | { |
1204 | 1302 | GtkTreeIter iter; |
1205 | 1303 | gchar *sample_path; |
1206 | gchar *name; | |
1207 | gchar *icon; | |
1208 | gchar type; | |
1209 | 1304 | GtkTreeModel *model; |
1305 | struct item *item = NULL; | |
1210 | 1306 | gint count = browser_get_selected_items_count (&local_browser); |
1211 | 1307 | |
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) | |
1219 | 1313 | { |
1220 | 1314 | browser_set_selected_row_iter (&local_browser, &iter); |
1221 | 1315 | 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); | |
1228 | 1335 | 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); | |
1236 | 1346 | } |
1237 | 1347 | |
1238 | 1348 | gtk_widget_set_sensitive (local_show_menuitem, count <= 1); |
1239 | 1349 | gtk_widget_set_sensitive (local_rename_menuitem, count == 1); |
1240 | 1350 | 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); | |
1242 | 1354 | |
1243 | 1355 | return FALSE; |
1244 | 1356 | } |
1253 | 1365 | double x_ratio, mid_y, value; |
1254 | 1366 | short *sample; |
1255 | 1367 | |
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); | |
1263 | 1369 | |
1264 | 1370 | context = gtk_widget_get_style_context (widget); |
1265 | 1371 | width = gtk_widget_get_allocated_width (widget); |
1275 | 1381 | for (i = 0; i < MAX_DRAW_X; i++) |
1276 | 1382 | { |
1277 | 1383 | x_sample = i * x_ratio; |
1278 | if (x_sample < audio.sample->len) | |
1384 | if (x_sample < audio.sample->len >> 1) | |
1279 | 1385 | { |
1280 | 1386 | x_widget = i * ((double) width) / MAX_DRAW_X; |
1281 | 1387 | value = mid_y - mid_y * (sample[x_sample] / (float) SHRT_MIN); |
1285 | 1391 | } |
1286 | 1392 | } |
1287 | 1393 | |
1288 | g_mutex_unlock (&audio.mutex); | |
1394 | g_mutex_unlock (&audio.control.mutex); | |
1289 | 1395 | |
1290 | 1396 | return FALSE; |
1291 | 1397 | } |
1295 | 1401 | { |
1296 | 1402 | GtkTreeIter iter; |
1297 | 1403 | GtkTreeModel *model; |
1298 | gchar *name; | |
1299 | 1404 | gchar *uri; |
1300 | 1405 | GVariant *params, *result; |
1301 | 1406 | GVariantBuilder builder; |
1302 | 1407 | GFile *file; |
1303 | 1408 | GDBusProxy *proxy; |
1409 | struct item *item; | |
1304 | 1410 | gchar *path = NULL; |
1305 | 1411 | gboolean done = FALSE; |
1306 | 1412 | gint count = browser_get_selected_items_count (&local_browser); |
1313 | 1419 | { |
1314 | 1420 | browser_set_selected_row_iter (&local_browser, &iter); |
1315 | 1421 | 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); | |
1319 | 1425 | } |
1320 | 1426 | else |
1321 | 1427 | { |
1369 | 1475 | { |
1370 | 1476 | GtkTreeIter iter; |
1371 | 1477 | GtkTreeModel *model; |
1372 | gchar *name; | |
1373 | 1478 | gchar *path; |
1374 | 1479 | gchar *uri; |
1375 | 1480 | GFile *file; |
1481 | struct item *item; | |
1376 | 1482 | |
1377 | 1483 | browser_set_selected_row_iter (&local_browser, &iter); |
1378 | 1484 | 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); | |
1382 | 1488 | |
1383 | 1489 | file = g_file_new_for_path (path); |
1384 | 1490 | g_free (path); |
1410 | 1516 | static gboolean |
1411 | 1517 | elektroid_autoplay_clicked (GtkWidget * object, gboolean state, gpointer data) |
1412 | 1518 | { |
1413 | autoplay = state; | |
1519 | preferences.autoplay = state; | |
1414 | 1520 | return FALSE; |
1415 | 1521 | } |
1416 | 1522 | |
1424 | 1530 | elektroid_set_volume_callback (gdouble value) |
1425 | 1531 | { |
1426 | 1532 | 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 (¬ifier, 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; | |
1609 | 1533 | } |
1610 | 1534 | |
1611 | 1535 | static void |
1634 | 1558 | pathname = |
1635 | 1559 | chain_path (browser->dir, gtk_entry_get_text (name_dialog_entry)); |
1636 | 1560 | |
1637 | err = browser->mkdir (pathname); | |
1638 | ||
1639 | if (err < 0) | |
1561 | err = browser->fs_ops->mkdir (pathname, &connector); | |
1562 | ||
1563 | if (err) | |
1640 | 1564 | { |
1641 | 1565 | show_error_msg (_("Error while creating dir “%s”: %s."), |
1642 | pathname, g_strerror (errno)); | |
1566 | pathname, g_strerror (err)); | |
1643 | 1567 | } |
1644 | 1568 | else |
1645 | 1569 | { |
1646 | browser->load_dir (NULL); | |
1570 | browser_load_dir (browser); | |
1647 | 1571 | } |
1648 | 1572 | |
1649 | 1573 | free (pathname); |
1675 | 1599 | else |
1676 | 1600 | { |
1677 | 1601 | 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); | |
1768 | 1602 | } |
1769 | 1603 | } |
1770 | 1604 | |
1831 | 1665 | static void |
1832 | 1666 | elektroid_stop_running_task (GtkWidget * object, gpointer data) |
1833 | 1667 | { |
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); | |
1837 | 1671 | } |
1838 | 1672 | |
1839 | 1673 | static gboolean |
1965 | 1799 | elektroid_complete_running_task (gpointer data) |
1966 | 1800 | { |
1967 | 1801 | 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); | |
1970 | 1803 | |
1971 | 1804 | if (elektroid_get_running_task (&iter)) |
1972 | 1805 | { |
1973 | 1806 | gtk_list_store_set (task_list_store, &iter, |
1974 | 1807 | TASK_LIST_STORE_STATUS_FIELD, |
1975 | sample_transfer.status, | |
1808 | transfer.status, | |
1976 | 1809 | TASK_LIST_STORE_STATUS_HUMAN_FIELD, status, -1); |
1977 | 1810 | 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); | |
1980 | 1813 | |
1981 | 1814 | gtk_widget_set_sensitive (cancel_task_button, FALSE); |
1982 | 1815 | } |
1995 | 1828 | enum elektroid_task_type type; |
1996 | 1829 | gchar *src; |
1997 | 1830 | gchar *dst; |
1831 | gint fs; | |
1998 | 1832 | 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); | |
2001 | 1836 | const gchar *status_human = elektroid_get_human_task_status (RUNNING); |
2002 | 1837 | |
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) | |
2008 | 1843 | { |
2009 | 1844 | gtk_list_store_set (task_list_store, &iter, |
2010 | 1845 | TASK_LIST_STORE_STATUS_FIELD, RUNNING, |
2015 | 1850 | gtk_tree_view_set_cursor (GTK_TREE_VIEW (task_tree_view), path, NULL, |
2016 | 1851 | FALSE); |
2017 | 1852 | 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 | ||
2023 | 1861 | if (type == UPLOAD) |
2024 | 1862 | { |
2025 | 1863 | task_thread = |
2048 | 1886 | static gpointer |
2049 | 1887 | elektroid_upload_task (gpointer data) |
2050 | 1888 | { |
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; | |
2083 | 1914 | 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) | |
2087 | 1917 | { |
2088 | 1918 | error_print ("Error while uploading\n"); |
2089 | sample_transfer.status = COMPLETED_ERROR; | |
1919 | transfer.status = COMPLETED_ERROR; | |
2090 | 1920 | } |
2091 | 1921 | else |
2092 | 1922 | { |
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; | |
2097 | 1927 | } |
2098 | 1928 | else |
2099 | 1929 | { |
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); | |
2116 | 1948 | g_idle_add (elektroid_complete_running_task, NULL); |
2117 | 1949 | g_idle_add (elektroid_run_next_task, NULL); |
2118 | 1950 | |
2121 | 1953 | |
2122 | 1954 | static void |
2123 | 1955 | elektroid_add_task (enum elektroid_task_type type, const char *src, |
2124 | const char *dst) | |
1956 | const char *dst, gint remote_fs_id) | |
2125 | 1957 | { |
2126 | 1958 | const gchar *status_human = elektroid_get_human_task_status (QUEUED); |
2127 | 1959 | const gchar *type_human = elektroid_get_human_task_type (type); |
1960 | const gchar *icon = elektroid_get_inventory_icon_for_fs (remote_fs_id); | |
1961 | ||
2128 | 1962 | |
2129 | 1963 | gtk_list_store_insert_with_values (task_list_store, NULL, -1, |
2130 | 1964 | TASK_LIST_STORE_STATUS_FIELD, QUEUED, |
2135 | 1969 | TASK_LIST_STORE_STATUS_HUMAN_FIELD, |
2136 | 1970 | status_human, |
2137 | 1971 | 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); | |
2139 | 1977 | |
2140 | 1978 | gtk_widget_set_sensitive (remove_tasks_button, TRUE); |
2141 | 1979 | } |
2142 | 1980 | |
2143 | 1981 | 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; | |
2147 | 1988 | gchar *path; |
2148 | struct dirent *dirent; | |
2149 | 1989 | 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; | |
2150 | 2153 | gchar *src_abs_path = chain_path (src_dir, rel_path); |
2151 | 2154 | 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); | |
2158 | 2169 | goto cleanup_not_dir; |
2159 | 2170 | } |
2160 | 2171 | |
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); | |
2164 | 2175 | goto cleanup; |
2165 | 2176 | } |
2166 | 2177 | |
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); | |
2197 | 2188 | |
2198 | 2189 | cleanup: |
2199 | closedir (dir); | |
2190 | free_item_iterator (&iter); | |
2200 | 2191 | cleanup_not_dir: |
2201 | 2192 | free (dst_abs_path); |
2202 | 2193 | free (src_abs_path); |
2203 | 2194 | } |
2204 | 2195 | |
2205 | 2196 | 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 | |
2366 | 2197 | elektroid_add_download_task (GtkTreeModel * model, |
2367 | 2198 | GtkTreePath * path, |
2368 | 2199 | GtkTreeIter * iter, gpointer data) |
2369 | 2200 | { |
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); | |
2376 | 2208 | } |
2377 | 2209 | |
2378 | 2210 | static void |
2380 | 2212 | { |
2381 | 2213 | gboolean queued; |
2382 | 2214 | GtkTreeIter iter; |
2215 | struct item_iterator item_iterator; | |
2383 | 2216 | GtkTreeSelection *selection = |
2384 | 2217 | gtk_tree_view_get_selection (GTK_TREE_VIEW (remote_browser.view)); |
2385 | 2218 | |
2388 | 2221 | return; |
2389 | 2222 | } |
2390 | 2223 | |
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); | |
2395 | 2231 | |
2396 | 2232 | gtk_widget_set_sensitive (rx_sysex_button, FALSE); |
2397 | 2233 | gtk_widget_set_sensitive (tx_sysex_button, FALSE); |
2451 | 2287 | else if (event->keyval == GDK_KEY_F2) |
2452 | 2288 | { |
2453 | 2289 | count = browser_get_selected_items_count (browser); |
2454 | if (count == 1) | |
2290 | if (count == 1 && browser->fs_ops->rename) | |
2455 | 2291 | { |
2456 | 2292 | elektroid_rename_item (NULL, browser); |
2457 | 2293 | } |
2459 | 2295 | } |
2460 | 2296 | else if (event->keyval == GDK_KEY_Delete) |
2461 | 2297 | { |
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) | |
2464 | 2300 | { |
2465 | 2301 | elektroid_delete_files (NULL, browser); |
2466 | 2302 | } |
2468 | 2304 | } |
2469 | 2305 | else if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_r) |
2470 | 2306 | { |
2471 | browser->load_dir (NULL); | |
2307 | browser_load_dir (browser); | |
2472 | 2308 | return TRUE; |
2473 | 2309 | } |
2474 | 2310 | else if (event->state & GDK_CONTROL_MASK |
2499 | 2335 | { |
2500 | 2336 | if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_Left) |
2501 | 2337 | { |
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 | } | |
2503 | 2345 | return TRUE; |
2504 | 2346 | } |
2505 | 2347 | else |
2519 | 2361 | { |
2520 | 2362 | if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_Right) |
2521 | 2363 | { |
2522 | elektroid_add_upload_tasks (NULL, NULL); | |
2364 | if (remote_browser.fs_ops->upload) | |
2365 | { | |
2366 | elektroid_add_upload_tasks (NULL, NULL); | |
2367 | } | |
2523 | 2368 | return TRUE; |
2524 | 2369 | } |
2525 | 2370 | else |
2529 | 2374 | } |
2530 | 2375 | |
2531 | 2376 | 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); | |
2532 | 2468 | } |
2533 | 2469 | |
2534 | 2470 | static void |
2546 | 2482 | } |
2547 | 2483 | |
2548 | 2484 | gtk_tree_model_get_value (GTK_TREE_MODEL (devices_list_store), |
2549 | &iter, 0, &cardv); | |
2485 | &iter, DEVICES_LIST_STORE_CARD_FIELD, &cardv); | |
2550 | 2486 | |
2551 | 2487 | card = g_value_get_uint (&cardv); |
2552 | 2488 | |
2557 | 2493 | |
2558 | 2494 | if (elektroid_check_connector ()) |
2559 | 2495 | { |
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); | |
2563 | 2574 | } |
2564 | 2575 | } |
2565 | 2576 | |
2576 | 2587 | gchar *path_dirname; |
2577 | 2588 | gchar *name; |
2578 | 2589 | gchar *dir; |
2579 | gchar *dest_path; | |
2580 | 2590 | GtkTreeIter iter; |
2581 | 2591 | gboolean queued; |
2582 | 2592 | GdkAtom type; |
2583 | 2593 | 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: | |
2680 | 2661 | gtk_drag_finish (context, TRUE, TRUE, time); |
2681 | 2662 | } |
2682 | 2663 | |
2686 | 2667 | GtkSelectionData * selection_data, |
2687 | 2668 | guint info, guint time, gpointer user_data) |
2688 | 2669 | { |
2670 | GdkAtom type; | |
2671 | gchar *type_name; | |
2689 | 2672 | struct browser *browser = user_data; |
2690 | 2673 | |
2691 | 2674 | switch (info) |
2699 | 2682 | (guchar *) browser->dnd_data->str, |
2700 | 2683 | browser->dnd_data->len); |
2701 | 2684 | |
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 | ||
2703 | 2690 | break; |
2704 | 2691 | default: |
2705 | 2692 | error_print ("DND type not supported\n"); |
2733 | 2720 | GtkTreePath *path; |
2734 | 2721 | GtkTreeModel *model; |
2735 | 2722 | GtkTreeIter iter; |
2736 | gchar type; | |
2737 | gchar *icon; | |
2738 | 2723 | gchar *spath; |
2739 | 2724 | gint tx; |
2740 | 2725 | gint ty; |
2741 | 2726 | GtkTreeSelection *selection; |
2727 | struct item *item; | |
2742 | 2728 | struct browser *browser = user_data; |
2743 | 2729 | |
2744 | 2730 | gtk_tree_view_convert_widget_to_bin_window_coords |
2765 | 2751 | model = |
2766 | 2752 | GTK_TREE_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (widget))); |
2767 | 2753 | 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)))) | |
2776 | 2762 | { |
2777 | 2763 | if (browser->dnd_timeout_function_id) |
2778 | 2764 | { |
2780 | 2766 | browser->dnd_timeout_function_id = 0; |
2781 | 2767 | } |
2782 | 2768 | 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); | |
2786 | 2773 | } |
2787 | 2774 | else |
2788 | 2775 | { |
2841 | 2828 | browser->dnd_timeout_function_id = 0; |
2842 | 2829 | } |
2843 | 2830 | 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); | |
2845 | 2832 | |
2846 | 2833 | return TRUE; |
2847 | 2834 | } |
2857 | 2844 | g_source_remove (browser->dnd_timeout_function_id); |
2858 | 2845 | browser->dnd_timeout_function_id = 0; |
2859 | 2846 | } |
2847 | } | |
2848 | ||
2849 | static void | |
2850 | elektroid_notify_local_dir_change (struct browser *browser) | |
2851 | { | |
2852 | notifier_set_dir (¬ifier, browser->dir); | |
2860 | 2853 | } |
2861 | 2854 | |
2862 | 2855 | static void |
2883 | 2876 | } |
2884 | 2877 | |
2885 | 2878 | static int |
2886 | elektroid_run (int argc, char *argv[], gchar * local_dir) | |
2879 | elektroid_run (int argc, char *argv[]) | |
2887 | 2880 | { |
2888 | 2881 | GtkBuilder *builder; |
2889 | 2882 | GtkCssProvider *css_provider; |
2965 | 2958 | GTK_WIDGET (gtk_builder_get_object (builder, "hostname_label")); |
2966 | 2959 | |
2967 | 2960 | 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")); | |
2968 | 2963 | waveform_draw_area = |
2969 | 2964 | GTK_WIDGET (gtk_builder_get_object (builder, "waveform_draw_area")); |
2970 | 2965 | play_button = GTK_WIDGET (gtk_builder_get_object (builder, "play_button")); |
3066 | 3061 | GTK_ENTRY (gtk_builder_get_object (builder, "remote_dir_entry")), |
3067 | 3062 | .menu = GTK_MENU (gtk_builder_get_object (builder, "remote_menu")), |
3068 | 3063 | .dir = malloc (PATH_MAX), |
3069 | .load_dir = elektroid_load_remote_dir, | |
3070 | 3064 | .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 | |
3074 | 3070 | }; |
3071 | remote_tree_view_index_column = | |
3072 | GTK_TREE_VIEW_COLUMN (gtk_builder_get_object | |
3073 | (builder, "remote_tree_view_index_column")); | |
3075 | 3074 | |
3076 | 3075 | g_signal_connect (gtk_tree_view_get_selection (remote_browser.view), |
3077 | 3076 | "changed", G_CALLBACK (browser_selection_changed), |
3097 | 3096 | g_signal_connect (remote_browser.view, "drag-data-get", |
3098 | 3097 | G_CALLBACK (elektroid_dnd_get), &remote_browser); |
3099 | 3098 | g_signal_connect (remote_browser.view, "drag-data-received", |
3100 | G_CALLBACK (elektroid_dnd_received), NULL); | |
3099 | G_CALLBACK (elektroid_dnd_received), &remote_browser); | |
3101 | 3100 | g_signal_connect (remote_browser.view, "drag-motion", |
3102 | 3101 | G_CALLBACK (elektroid_drag_motion_list), &remote_browser); |
3103 | 3102 | g_signal_connect (remote_browser.view, "drag-leave", |
3106 | 3105 | G_CALLBACK (elektroid_drag_motion_up), &remote_browser); |
3107 | 3106 | g_signal_connect (remote_browser.up_button, "drag-leave", |
3108 | 3107 | 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); | |
3117 | 3108 | |
3118 | 3109 | gtk_drag_source_set ((GtkWidget *) remote_browser.view, GDK_BUTTON1_MASK, |
3119 | 3110 | TARGET_ENTRIES_REMOTE_SRC, TARGET_ENTRIES_REMOTE_SRC_N, |
3140 | 3131 | GTK_ENTRY (gtk_builder_get_object (builder, "local_dir_entry")), |
3141 | 3132 | .menu = GTK_MENU (gtk_builder_get_object (builder, "local_menu")), |
3142 | 3133 | .dir = malloc (PATH_MAX), |
3143 | .load_dir = elektroid_load_local_dir, | |
3144 | 3134 | .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 | |
3148 | 3141 | }; |
3149 | 3142 | |
3150 | 3143 | g_signal_connect (gtk_tree_view_get_selection (local_browser.view), |
3171 | 3164 | g_signal_connect (local_browser.view, "drag-data-get", |
3172 | 3165 | G_CALLBACK (elektroid_dnd_get), &local_browser); |
3173 | 3166 | g_signal_connect (local_browser.view, "drag-data-received", |
3174 | G_CALLBACK (elektroid_dnd_received), NULL); | |
3167 | G_CALLBACK (elektroid_dnd_received), &local_browser); | |
3175 | 3168 | g_signal_connect (local_browser.view, "drag-motion", |
3176 | 3169 | G_CALLBACK (elektroid_drag_motion_list), &local_browser); |
3177 | 3170 | g_signal_connect (local_browser.view, "drag-leave", |
3183 | 3176 | |
3184 | 3177 | sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (local_browser.view)); |
3185 | 3178 | gtk_tree_sortable_set_sort_func (sortable, BROWSER_LIST_STORE_NAME_FIELD, |
3186 | browser_sort, NULL, NULL); | |
3179 | browser_sort_samples, NULL, NULL); | |
3187 | 3180 | gtk_tree_sortable_set_sort_column_id (sortable, |
3188 | 3181 | BROWSER_LIST_STORE_NAME_FIELD, |
3189 | 3182 | GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID); |
3199 | 3192 | TARGET_ENTRIES_UP_BUTTON_DST, |
3200 | 3193 | TARGET_ENTRIES_UP_BUTTON_DST_N, GDK_ACTION_COPY); |
3201 | 3194 | |
3202 | audio_init (&audio, elektroid_set_volume_callback); | |
3195 | audio_init (&audio, elektroid_set_volume_callback, elektroid_redraw_sample); | |
3203 | 3196 | |
3204 | 3197 | devices_list_store = |
3205 | 3198 | GTK_LIST_STORE (gtk_builder_get_object (builder, "devices_list_store")); |
3232 | 3225 | |
3233 | 3226 | gtk_statusbar_push (status_bar, 0, _("Not connected")); |
3234 | 3227 | 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); | |
3236 | 3234 | |
3237 | 3235 | gtk_widget_set_sensitive (remote_box, FALSE); |
3238 | 3236 | gtk_widget_set_sensitive (rx_sysex_button, FALSE); |
3239 | 3237 | gtk_widget_set_sensitive (tx_sysex_button, FALSE); |
3240 | 3238 | gtk_widget_set_sensitive (os_upgrade_button, FALSE); |
3241 | 3239 | |
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 | |
3243 | 3242 | |
3244 | 3243 | gethostname (hostname, LABEL_MAX); |
3245 | 3244 | gtk_label_set_text (GTK_LABEL (hostname_label), hostname); |
3246 | 3245 | |
3247 | strcpy (local_browser.dir, local_dir); | |
3248 | local_browser.load_dir (NULL); | |
3249 | 3246 | debug_print (1, "Creating notifier thread...\n"); |
3250 | notifier_init (¬ifier, elektroid_load_local_dir, | |
3251 | elektroid_go_up_local_dir); | |
3252 | notifier_set_dir (¬ifier, local_dir); | |
3247 | notifier_init (¬ifier, &local_browser); | |
3248 | notifier_set_dir (¬ifier, preferences.local_dir); | |
3253 | 3249 | notifier_thread = g_thread_new ("notifier_thread", notifier_run, ¬ifier); |
3254 | free (local_dir); | |
3255 | 3250 | |
3256 | 3251 | gtk_widget_show (main_window); |
3257 | 3252 | gtk_main (); |
3258 | 3253 | |
3259 | 3254 | free (remote_browser.dir); |
3260 | free (local_browser.dir); | |
3261 | 3255 | |
3262 | 3256 | if (connector_check (&connector)) |
3263 | 3257 | { |
3265 | 3259 | } |
3266 | 3260 | |
3267 | 3261 | audio_destroy (&audio); |
3268 | return 0; | |
3262 | return EXIT_SUCCESS; | |
3269 | 3263 | } |
3270 | 3264 | |
3271 | 3265 | static gboolean |
3279 | 3273 | elektroid_print_help (gchar * executable_path) |
3280 | 3274 | { |
3281 | 3275 | gchar *exec_name; |
3282 | struct option *option; | |
3276 | const struct option *option; | |
3283 | 3277 | |
3284 | 3278 | fprintf (stderr, "%s\n", PACKAGE_STRING); |
3285 | 3279 | exec_name = basename (executable_path); |
3286 | 3280 | fprintf (stderr, "Usage: %s [options]\n", exec_name); |
3287 | 3281 | fprintf (stderr, "Options:\n"); |
3288 | option = options; | |
3282 | option = ELEKTROID_OPTIONS; | |
3289 | 3283 | while (option->name) |
3290 | 3284 | { |
3291 | 3285 | fprintf (stderr, " --%s, -%c", option->name, option->val); |
3301 | 3295 | int |
3302 | 3296 | main (int argc, char *argv[]) |
3303 | 3297 | { |
3304 | gint opt; | |
3298 | gint opt, ret; | |
3305 | 3299 | gchar *local_dir = NULL; |
3306 | 3300 | gint vflg = 0, dflg = 0, errflg = 0; |
3307 | 3301 | int long_index = 0; |
3314 | 3308 | bindtextdomain (PACKAGE, LOCALEDIR); |
3315 | 3309 | textdomain (PACKAGE); |
3316 | 3310 | |
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) | |
3318 | 3314 | { |
3319 | 3315 | switch (opt) |
3320 | 3316 | { |
3349 | 3345 | exit (EXIT_FAILURE); |
3350 | 3346 | } |
3351 | 3347 | |
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; |
25 | 25 | #include "utils.h" |
26 | 26 | |
27 | 27 | void |
28 | notifier_init (struct notifier *notifier, GSourceFunc refresh_dir, | |
29 | GSourceFunc up_dir) | |
28 | notifier_init (struct notifier *notifier, struct browser *browser) | |
30 | 29 | { |
31 | 30 | notifier->fd = inotify_init (); |
32 | 31 | notifier->wd = -1; |
33 | 32 | notifier->event_size = sizeof (struct inotify_event) + PATH_MAX; |
34 | 33 | notifier->event = malloc (notifier->event_size); |
35 | 34 | notifier->running = 1; |
36 | notifier->refresh_dir = refresh_dir; | |
37 | notifier->up_dir = up_dir; | |
35 | notifier->browser = browser; | |
38 | 36 | } |
39 | 37 | |
40 | 38 | void |
41 | 39 | notifier_set_dir (struct notifier *notifier, gchar * path) |
42 | 40 | { |
41 | debug_print (1, "Changing notifier path to %s...\n", path); | |
43 | 42 | if (notifier->fd < 0) |
44 | 43 | { |
45 | 44 | return; |
51 | 50 | notifier->wd = |
52 | 51 | inotify_add_watch (notifier->fd, path, |
53 | 52 | IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_DELETE_SELF |
54 | | IN_MOVE_SELF); | |
53 | | IN_MOVE_SELF | IN_MOVED_TO); | |
55 | 54 | } |
56 | 55 | |
57 | 56 | void |
72 | 71 | notifier_free (struct notifier *notifier) |
73 | 72 | { |
74 | 73 | 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; | |
75 | 82 | } |
76 | 83 | |
77 | 84 | gpointer |
98 | 105 | |
99 | 106 | if (notifier->event->mask & IN_CREATE |
100 | 107 | || 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) | |
102 | 110 | { |
103 | 111 | debug_print (1, "Reloading local dir...\n"); |
104 | g_idle_add (notifier->refresh_dir, NULL); | |
112 | g_idle_add (browser_load_dir, notifier->browser); | |
105 | 113 | } |
106 | 114 | 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) | |
108 | 117 | { |
109 | 118 | 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); | |
111 | 120 | } |
112 | 121 | else |
113 | 122 | { |
19 | 19 | |
20 | 20 | #include <sys/inotify.h> |
21 | 21 | #include <gtk/gtk.h> |
22 | #include "browser.h" | |
22 | 23 | |
23 | 24 | struct notifier |
24 | 25 | { |
27 | 28 | size_t event_size; |
28 | 29 | struct inotify_event *event; |
29 | 30 | gint running; |
30 | GSourceFunc refresh_dir; | |
31 | GSourceFunc up_dir; | |
31 | struct browser *browser; | |
32 | 32 | }; |
33 | 33 | |
34 | void notifier_init (struct notifier *, GSourceFunc, GSourceFunc); | |
34 | void notifier_init (struct notifier *, struct browser *); | |
35 | 35 | |
36 | 36 | void notifier_set_dir (struct notifier *, gchar *); |
37 | 37 |
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 *); |
22 | 22 | #include <samplerate.h> |
23 | 23 | #include <inttypes.h> |
24 | 24 | #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) | |
29 | 155 | { |
30 | 156 | SF_INFO sf_info; |
31 | 157 | 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; | |
38 | 172 | sf_info.channels = 1; |
39 | 173 | 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); | |
41 | 175 | if (!sndfile) |
42 | 176 | { |
43 | 177 | error_print ("%s\n", sf_strerror (sndfile)); |
44 | 178 | return -1; |
45 | 179 | } |
46 | 180 | |
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); | |
48 | 217 | |
49 | 218 | sf_close (sndfile); |
50 | 219 | |
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; | |
52 | 252 | } |
53 | 253 | |
54 | 254 | static void |
71 | 271 | } |
72 | 272 | } |
73 | 273 | |
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) | |
77 | 278 | { |
78 | 279 | SF_INFO sf_info; |
79 | 280 | SNDFILE *sndfile; |
80 | 281 | SRC_DATA src_data; |
81 | 282 | 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); | |
102 | 305 | } |
103 | 306 | |
104 | 307 | 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); | |
106 | 309 | if (!sndfile) |
107 | 310 | { |
108 | 311 | error_print ("%s\n", sf_strerror (sndfile)); |
109 | 312 | return -1; |
110 | 313 | } |
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; | |
111 | 335 | |
112 | 336 | //Set scale factor. See http://www.mega-nerd.com/libsndfile/api.html#note2 |
113 | 337 | if ((sf_info.format & SF_FORMAT_FLOAT) == SF_FORMAT_FLOAT || |
119 | 343 | } |
120 | 344 | |
121 | 345 | 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)); | |
126 | 350 | 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; | |
128 | 352 | |
129 | 353 | 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)); | |
132 | 356 | |
133 | 357 | src_state = src_new (SRC_SINC_BEST_QUALITY, 1, &err); |
134 | 358 | if (err) |
141 | 365 | *frames = sf_info.frames * src_data.src_ratio; |
142 | 366 | } |
143 | 367 | |
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); | |
145 | 379 | |
146 | 380 | 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) | |
157 | 393 | { |
158 | 394 | debug_print (2, "Loading buffer...\n"); |
159 | 395 | |
182 | 418 | buffer_input = buffer_input_mono; |
183 | 419 | } |
184 | 420 | |
185 | if (sf_info.samplerate == 48000) | |
186 | { | |
187 | if (mutex) | |
421 | if (sf_info.samplerate == ELEKTRON_SAMPLE_RATE) | |
422 | { | |
423 | if (control) | |
188 | 424 | { |
189 | g_mutex_lock (mutex); | |
425 | g_mutex_lock (&control->mutex); | |
190 | 426 | } |
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) | |
193 | 430 | { |
194 | g_mutex_unlock (mutex); | |
431 | g_mutex_unlock (&control->mutex); | |
195 | 432 | } |
196 | 433 | } |
197 | 434 | else |
207 | 444 | } |
208 | 445 | src_float_to_short_array (src_data.data_out, buffer_s, |
209 | 446 | src_data.output_frames_gen); |
210 | if (mutex) | |
447 | if (control) | |
211 | 448 | { |
212 | g_mutex_lock (mutex); | |
449 | g_mutex_lock (&control->mutex); | |
213 | 450 | } |
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) | |
216 | 454 | { |
217 | g_mutex_unlock (mutex); | |
455 | g_mutex_unlock (&control->mutex); | |
218 | 456 | } |
219 | 457 | } |
220 | 458 | |
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); | |
234 | 465 | } |
235 | 466 | } |
236 | 467 | |
242 | 473 | src_strerror (err)); |
243 | 474 | } |
244 | 475 | |
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); | |
263 | 490 | } |
264 | 491 | |
265 | 492 | cleanup: |
271 | 498 | |
272 | 499 | sf_close (sndfile); |
273 | 500 | |
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 | } |
20 | 20 | #include <glib.h> |
21 | 21 | #include <sys/types.h> |
22 | 22 | #include <sys/stat.h> |
23 | #include "utils.h" | |
23 | 24 | |
24 | #define LOAD_BUFFER_LEN 4800 | |
25 | #ifndef SAMPLE_H | |
26 | #define SAMPLE_H | |
25 | 27 | |
26 | size_t sample_save (GArray *, gchar *); | |
28 | #define LOAD_BUFFER_LEN 4800 // In guint16 frames; 9600 B; 0.1 ms | |
27 | 29 | |
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 |
17 | 17 | * along with Elektroid. If not, see <http://www.gnu.org/licenses/>. |
18 | 18 | */ |
19 | 19 | |
20 | #include <glib.h> | |
21 | 20 | #include <stdio.h> |
22 | 21 | #include <wordexp.h> |
22 | #include <errno.h> | |
23 | 23 | #include "utils.h" |
24 | 24 | |
25 | 25 | #define DEBUG_SHORT_HEX_LEN 64 |
26 | 26 | #define DEBUG_FULL_HEX_THRES 3 |
27 | 27 | |
28 | #define REG_TYPE "elektroid-wave-symbolic" | |
29 | #define DIR_TYPE "folder-visiting-symbolic" | |
28 | #define KIB 1024 | |
30 | 29 | |
31 | 30 | gint debug_level; |
32 | 31 | |
148 | 147 | int i = namelen; |
149 | 148 | const gchar *ext = &name[namelen]; |
150 | 149 | |
151 | while (*(ext - 1) != '.' && i > 0) | |
150 | while (i > 0 && *(ext - 1) != '.') | |
152 | 151 | { |
153 | 152 | ext--; |
154 | 153 | i--; |
164 | 163 | } |
165 | 164 | } |
166 | 165 | |
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; | |
197 | 180 | } |
198 | 181 | |
199 | 182 | char * |
201 | 184 | { |
202 | 185 | DIR *dir; |
203 | 186 | gchar *startup_path = NULL; |
204 | wordexp_t exp_result; | |
205 | 187 | |
206 | 188 | if (local_dir) |
207 | 189 | { |
213 | 195 | } |
214 | 196 | else |
215 | 197 | { |
216 | error_print ("Unable to open dir %s\n", local_dir); | |
198 | error_print ("Unable to open dir '%s'\n", local_dir); | |
217 | 199 | } |
218 | 200 | closedir (dir); |
219 | 201 | } |
220 | 202 | |
221 | 203 | if (!startup_path) |
222 | 204 | { |
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); | |
230 | 209 | |
231 | 210 | return startup_path; |
232 | 211 | } |
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 | } |
18 | 18 | */ |
19 | 19 | |
20 | 20 | #include <stdio.h> |
21 | #include <glib.h> | |
22 | ||
23 | #ifndef UTILS_H | |
24 | #define UTILS_H | |
21 | 25 | |
22 | 26 | #define LABEL_MAX 128 |
23 | 27 | |
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 | |
27 | 30 | |
28 | 31 | #define debug_print(level, format, ...) if (level <= debug_level) fprintf(stderr, "DEBUG:" __FILE__ ":%d:(%s): " format, __LINE__, __FUNCTION__, ## __VA_ARGS__) |
29 | 32 | #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 | }; | |
30 | 118 | |
31 | 119 | extern int debug_level; |
32 | 120 | |
42 | 130 | |
43 | 131 | gchar get_type_from_inventory_icon (const gchar *); |
44 | 132 | |
45 | const gchar *get_inventory_icon_from_type (gchar); | |
133 | gchar *get_expanded_dir (const char *); | |
46 | 134 | |
47 | 135 | 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 | |
1 | 1 | |
2 | 2 | EXTRA_DIST = \ |
3 | 3 | $(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 | #!/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 |