Bug Summary

File:build-analysis/../src/plugins/midsquash/midsquash.c
Warning:line 214, column 3
Value stored to 'ret' is never read

Annotated Source Code

1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2017 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * ---------------------------------
17 *
18 * MIDISquash helper plugin for XMMS2 by Adam Nielsen <malvineous@shikadi.net>
19 *
20 * This file implements a MIDI "squash" xform plugin, which converts multiple
21 * MIDI tracks (like you might find in a format-1 .mid file) into a single
22 * track (like in a format-0 file.)
23 *
24 * Since the FluidSynth plugin is only designed to accept a single MIDI track,
25 * all multi-track files must be converted to a single track to be played.
26 * Rather than require each format handler to do this conversion itself,
27 * those handlers can provide the MIDI data in audio/miditracks format, and
28 * this plugin will take care of the conversion.
29 *
30 * The audio/miditracks format is simply a list of chunks, where each chunk
31 * contains a four-byte big endian length value, followed by that many
32 * bytes of standard MIDI data. It's like the MTrk chunks in a normal MIDI
33 * file joined one after the other, just without the "MTrk" text.
34 */
35
36#include <xmms/xmms_xformplugin.h>
37#include <xmms/xmms_sample.h>
38#include <xmms/xmms_medialib.h>
39#include <xmms/xmms_log.h>
40
41#include <glib.h>
42#include <string.h>
43#include <unistd.h>
44#include <stdlib.h>
45#include <ctype.h>
46
47/*
48 * Type definitions
49 */
50
51typedef struct xmms_midsquash_data_St {
52 GString *midi0_data;
53 gulong pos;
54} xmms_midsquash_data_t;
55
56typedef struct xmms_midsquash_event_St {
57 gulong time;
58 guchar running_status; /* 0 or the last event if this uses running status */
59 gchar *offset;
60 gulong length;
61} xmms_midsquash_event_t;
62
63/*
64 * Function prototypes
65 */
66
67static gboolean xmms_midsquash_plugin_setup (xmms_xform_plugin_t *xform_plugin);
68static gint xmms_midsquash_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err);
69static void xmms_midsquash_destroy (xmms_xform_t *xform);
70static gboolean xmms_midsquash_init (xmms_xform_t *xform);
71static gint64 xmms_midsquash_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err);
72static gulong xmms_midisquash_read_midi_num (const gchar *s, gulong *j);
73static gint xmms_midsquash_sort_events(gconstpointer a, gconstpointer b);
74
75/*
76 * Plugin header
77 */
78XMMS_XFORM_PLUGIN_DEFINE ("midsquash",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC
= { XMMS_PLUGIN_TYPE_XFORM, 7, "midsquash", "Multitrack MIDI squasher"
, "clang-analysis", "Multitrack MIDI squasher", (gboolean (*)
(gpointer))xmms_midsquash_plugin_setup };
79 "Multitrack MIDI squasher",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC
= { XMMS_PLUGIN_TYPE_XFORM, 7, "midsquash", "Multitrack MIDI squasher"
, "clang-analysis", "Multitrack MIDI squasher", (gboolean (*)
(gpointer))xmms_midsquash_plugin_setup };
80 XMMS_VERSION,xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC
= { XMMS_PLUGIN_TYPE_XFORM, 7, "midsquash", "Multitrack MIDI squasher"
, "clang-analysis", "Multitrack MIDI squasher", (gboolean (*)
(gpointer))xmms_midsquash_plugin_setup };
81 "Multitrack MIDI squasher",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC
= { XMMS_PLUGIN_TYPE_XFORM, 7, "midsquash", "Multitrack MIDI squasher"
, "clang-analysis", "Multitrack MIDI squasher", (gboolean (*)
(gpointer))xmms_midsquash_plugin_setup };
82 xmms_midsquash_plugin_setup)xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC
= { XMMS_PLUGIN_TYPE_XFORM, 7, "midsquash", "Multitrack MIDI squasher"
, "clang-analysis", "Multitrack MIDI squasher", (gboolean (*)
(gpointer))xmms_midsquash_plugin_setup };
;
83
84static gboolean
85xmms_midsquash_plugin_setup (xmms_xform_plugin_t *xform_plugin)
86{
87 xmms_xform_methods_t methods;
88
89 XMMS_XFORM_METHODS_INIT (methods)memset (&methods, 0, sizeof (xmms_xform_methods_t));
90 methods.init = xmms_midsquash_init;
91 methods.destroy = xmms_midsquash_destroy;
92 methods.read = xmms_midsquash_read;
93 methods.seek = xmms_midsquash_seek;
94
95 xmms_xform_plugin_methods_set (xform_plugin, &methods);
96
97 /*
98 xmms_plugin_info_add (plugin, "URL", "http://www.xmms2.org/");
99 xmms_plugin_info_add (plugin, "Author", "Adam Nielsen <malvineous@shikadi.net>");
100 xmms_plugin_info_add (plugin, "License", "LGPL");
101 */
102
103 xmms_xform_plugin_indata_add (xform_plugin,
104 XMMS_STREAM_TYPE_MIMETYPE,
105 "audio/miditracks",
106 XMMS_STREAM_TYPE_END);
107 return TRUE(!(0));
108}
109
110static void
111xmms_midsquash_destroy (xmms_xform_t *xform)
112{
113 xmms_midsquash_data_t *data;
114
115 g_return_if_fail (xform)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*)
0), ((const char*) (__func__)), "xform"); return; }; }while (
0)
;
116
117 data = xmms_xform_private_data_get (xform);
118 g_return_if_fail (data)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "data"); return; }; }while (0)
;
119
120 if (data->midi0_data)
121 g_string_free (data->midi0_data, TRUE(!(0)));
122
123 g_free (data);
124}
125
126/* Seeking is in bytes. This assumes the calling function is smart enough not
127 * to seek past the start or end of the file.
128 */
129static gint64
130xmms_midsquash_seek (xmms_xform_t *xform, gint64 samples,
131 xmms_xform_seek_mode_t whence, xmms_error_t *err)
132{
133 xmms_midsquash_data_t *data;
134 g_return_val_if_fail (xform, -1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*)
0), ((const char*) (__func__)), "xform"); return (-1); }; }while
(0)
;
135
136 data = xmms_xform_private_data_get (xform);
137 g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "data"); return (-1); }; }while
(0)
;
138
139 /* Adjust our internal pointer by the seek amount */
140 switch (whence) {
141 case XMMS_XFORM_SEEK_CUR:
142 data->pos += samples;
143 break;
144 case XMMS_XFORM_SEEK_SET:
145 data->pos = samples;
146 break;
147 case XMMS_XFORM_SEEK_END:
148 data->pos = data->midi0_data->len + samples;
149 break;
150 }
151
152 return data->pos;
153}
154
155static gulong
156xmms_midisquash_read_midi_num (const gchar *s, gulong *j)
157{
158 gint i;
159 gulong val = 0;
160
161 for (i = 0; i < 4; i++) {
162 val |= s[*j] & 0x7F;
163 if (s[(*j)++] & 0x80) val <<= 7;
164 else break;
165 }
166
167 return val;
168}
169
170static gint
171xmms_midsquash_sort_events(gconstpointer a, gconstpointer b)
172{
173 xmms_midsquash_event_t *ta = (xmms_midsquash_event_t *)a;
174 xmms_midsquash_event_t *tb = (xmms_midsquash_event_t *)b;
175 if (ta->time == tb->time) return 0;
176 if (ta->time < tb->time) return -1;
177 return 1;
178}
179
180static gboolean
181xmms_midsquash_init (xmms_xform_t *xform)
182{
183 xmms_error_t error;
184 xmms_midsquash_data_t *data;
185 gulong track_len, len;
186 gint32 ticks_per_quarter_note;
187 const gchar *metakey;
188 guchar buf[4096];
189 gint ret;
190 guchar prev_event = 0;
191 GArray *events = NULL((void*)0);
192 GArray *track_data = NULL((void*)0);
193
194 g_return_val_if_fail (xform, FALSE)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*)
0), ((const char*) (__func__)), "xform"); return ((0)); }; }
while (0)
;
195
196 data = g_new0 (xmms_midsquash_data_t, 1)((xmms_midsquash_data_t *) g_malloc0_n ((1), sizeof (xmms_midsquash_data_t
)))
;
197 xmms_xform_private_data_set (xform, data);
198
199 data->midi0_data = NULL((void*)0);
200
201 if (!xmms_xform_auxdata_get_intxmms_xform_auxdata_get_int32 (xform, "tempo", &ticks_per_quarter_note)) {
202 XMMS_DBG ("MIDI xform missing 'tempo' auxdata value")g_debug ("../src/plugins/midsquash/midsquash.c" ":" "202" ": "
"MIDI xform missing 'tempo' auxdata value")
;
203 goto error_cleanup;
204 }
205 xmms_xform_auxdata_set_int (xform, "tempo", ticks_per_quarter_note);
206
207 /* Load all the tracks */
208 events = g_array_new(FALSE(0), FALSE(0), sizeof(xmms_midsquash_event_t));
209 track_data = g_array_new(FALSE(0), FALSE(0), sizeof(GString *));
210 while (xmms_xform_read (xform, buf, 4, &error) == 4) {
211 track_len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
212 GString *t = g_string_sized_new(track_len);
213
214 ret = xmms_xform_read (xform, t->str, track_len, &error);
Value stored to 'ret' is never read
215
216 g_array_append_val(track_data, t)g_array_append_vals (track_data, &(t), 1);
217
218 /* Run through the MIDI data in this track, and convert it to a list of
219 * events in absolute ticks (instead of delta ticks.)
220 */
221 gulong i = 0;
222 gulong abs_ticks = 0;
223 while (i < track_len) {
224 abs_ticks += xmms_midisquash_read_midi_num(t->str, &i);
225
226 xmms_midsquash_event_t event;
227 gboolean ignore_event = FALSE(0);
228 event.time = abs_ticks;
229 event.offset = &t->str[i];
230 gulong i0 = i;
231
232 /* Read MIDI event */
233 guchar midi_event = t->str[i];
234
235 if (!(midi_event & 0x80)) {
236 /* This is a running-status byte */
237 midi_event = prev_event;
238 event.running_status = prev_event;
239 } else {
240 if ((midi_event & 0xF0) != 0xF0) {
241 /* Meta events (0xF0 through 0xFF) can appear in the middle of
242 * running-status data without affecting the running status, so we
243 * only update the 'last event' if this isn't a meta-event.
244 */
245 prev_event = midi_event;
246 }
247 event.running_status = 0;
248 i++;
249 }
250
251 switch (midi_event & 0xF0) {
252 case 0x80: /* Note off (two bytes) */ i += 2; break;
253 case 0x90: /* Note on (two bytes) */ i += 2; break;
254 case 0xA0: /* Key pressure (two bytes) */ i += 2; break;
255 case 0xB0: /* Controller change (two bytes) */ i += 2; break;
256 case 0xC0: /* Instrument change (one byte) */ i += 1; break;
257 case 0xD0: /* Channel pressure (one byte) */ i += 1; break;
258 case 0xE0: /* Pitch bend (two bytes) */ i += 2; break;
259 case 0xF0: {
260 if (midi_event == 0xFF) { /* Meta-event */
261 if (t->str[i] == 0x2F) {
262 /* This is an end-of-track event, so we need to ignore it
263 * otherwise the song will end as soon as we encounter the end
264 * of the shortest track (which could be quite early on.)
265 */
266 ignore_event = TRUE(!(0));
267 }
268 i++; /* event type */
269 } /* else sysex */
270 len = xmms_midisquash_read_midi_num(t->str, &i);
271 i += len;
272 break;
273 }
274 default:
275 XMMS_DBG ("Corrupted MIDI file (invalid event 0x%02X)", midi_event)g_debug ("../src/plugins/midsquash/midsquash.c" ":" "275" ": "
"Corrupted MIDI file (invalid event 0x%02X)", midi_event)
;
276 goto error_cleanup;
277 }
278 event.length = i - i0;
279 if (!ignore_event)
280 g_array_append_val(events, event)g_array_append_vals (events, &(event), 1);
281 } /* end loop: run through all the track's events */
282 }
283
284 /* Now that all the events have been read in, in absolute time, sorting them
285 * will put them all in playable order.
286 */
287 g_array_sort(events, xmms_midsquash_sort_events);
288
289 /* Now copy all the sorted events into a big array, which will be used as
290 * the output data.
291 */
292 data->midi0_data = g_string_new("");
293 gulong last_time = 0;
294 guint64 playtime_us = 0;
295 gulong us_per_quarter_note = 500000;
296 gulong i, j;
297 guchar val;
298 for (i = 0; i < events->len; i++) {
299 xmms_midsquash_event_t *e;
300 e = &g_array_index(events, xmms_midsquash_event_t, i)(((xmms_midsquash_event_t*) (void *) (events)->data) [(i)]
)
;
301
302 /* Calculate the delta time and write it out in MIDI style */
303 gulong delta_ticks = e->time - last_time;
304 if (delta_ticks & (0x7F << 21)) {
305 val = ((delta_ticks >> 21) & 0x7F) | 0x80;
306 g_string_append_len(data->midi0_data, (gchar *)&val, 1);
307 }
308 if (delta_ticks & ((0x7F << 21) | (0x7F << 14))) {
309 val = ((delta_ticks >> 14) & 0x7F) | 0x80;
310 g_string_append_len(data->midi0_data, (gchar *)&val, 1);
311 }
312 if (delta_ticks & ((0x7F << 21) | (0x7F << 14) | (0x7F << 7))) {
313 val = ((delta_ticks >> 7) & 0x7F) | 0x80;
314 g_string_append_len(data->midi0_data, (gchar *)&val, 1);
315 }
316 val = delta_ticks & 0x7F;
317 g_string_append_len(data->midi0_data, (gchar *)&val, 1);
318 last_time = e->time;
319
320 if (e->running_status) {
321 /* This event is a continuation of the previous event, but since we're
322 * combining all the events the previous event may no longer be the same,
323 * so we take the easy way out and just write the event out in full here.
324 */
325 g_string_append_len(data->midi0_data, (gchar *)&e->running_status, 1);
326 }
327
328 /* Copy the actual event across from the track data */
329 g_string_append_len(data->midi0_data, e->offset, e->length);
330
331 /* Check for a tempo change event */
332 if ((e->offset[0] & 0xF0) == 0xF0) {
333 if (e->offset[1] == 0x51) { /* tempo event */
334 j = 2;
335 len = xmms_midisquash_read_midi_num(e->offset, &j);
336 len += j;
337 us_per_quarter_note = 0;
338 for (; j < len; j++) {
339 us_per_quarter_note <<= 8;
340 us_per_quarter_note |= (unsigned char)(e->offset[j]);
341 }
342 }
343 }
344
345 /* Update the song length */
346 playtime_us += delta_ticks * (us_per_quarter_note / ticks_per_quarter_note);
347 }
348
349 xmms_xform_outdata_type_add (xform,
350 XMMS_STREAM_TYPE_MIMETYPE,
351 "audio/rawmidi",
352 XMMS_STREAM_TYPE_FMT_CHANNELS,
353 16,
354 XMMS_STREAM_TYPE_END);
355
356
357 metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION"duration";
358 xmms_xform_metadata_set_int (xform, metakey,
359 playtime_us / 1000);
360
361 ret = TRUE(!(0));
362
363always_cleanup:
364
365 /* Release all the track and event data */
366 if (track_data) {
367 for (i = 0; i < track_data->len; i++) {
368 g_string_free(g_array_index(track_data, GString *, i)(((GString **) (void *) (track_data)->data) [(i)]), TRUE(!(0)));
369 }
370 g_array_free(track_data, TRUE(!(0)));
371 }
372
373 if (events)
374 g_array_free(events, TRUE(!(0)));
375
376 return ret;
377
378error_cleanup:
379
380 /* Don't need to free data->midi0_data as we don't goto cleanup after it
381 * has been allocated.
382 */
383
384 g_free (data);
385
386 ret = FALSE(0);
387 goto always_cleanup;
388}
389
390static gint
391xmms_midsquash_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err)
392{
393 xmms_midsquash_data_t *data;
394 data = xmms_xform_private_data_get (xform);
395
396 if (data->pos + len > data->midi0_data->len)
397 len = data->midi0_data->len - data->pos;
398
399 memcpy(buf, &(data->midi0_data->str[data->pos]), len);
400 data->pos += len;
401
402 return len;
403}