diff --git a/src/tools/dfffile.c b/src/tools/dfffile.c index dd40be4bd..c2e4db22e 100644 --- a/src/tools/dfffile.c +++ b/src/tools/dfffile.c @@ -14,22 +14,25 @@ #include "dfffile.h" +#define BLOCKSIZE 8192 + struct dff_file { - uint8_t *data; - size_t size; + uint8_t *buffer; + size_t blocksize; + size_t offset; int mode; - int fd; + bool close; + FILE *file; + size_t pos; struct dff_file_info info; - - uint8_t *p; - size_t offset; }; struct dff_chunk { uint32_t id; uint64_t size; + uint64_t pos; void *data; }; @@ -57,28 +60,44 @@ static inline uint64_t parse_be64(const uint8_t *in) return res; } -static inline int f_avail(struct dff_file *f) +static inline int f_read(struct dff_file *f, void *data, size_t size) { - if (f->p < f->data + f->size) - return f->size + f->data - f->p; + size_t s = fread(data, 1, size, f->file); + f->pos += s; + if (s < size) + return -1; return 0; } static int read_chunk(struct dff_file *f, struct dff_chunk *c) { - if (f_avail(f) < 12) + uint8_t data[12]; + + if (f_read(f, data, sizeof(data)) < 0) return -ENOSPC; - c->id = parse_be32(f->p); /* id of this chunk */ - c->size = parse_be64(f->p + 4); /* size of this chunk */ - f->p += 12; - c->data = f->p; + c->id = parse_be32(data); /* id of this chunk */ + c->size = parse_be64(data + 4); /* size of this chunk */ + c->pos = f->pos; return 0; } static int skip_chunk(struct dff_file *f, const struct dff_chunk *c) { - f->p = SPA_PTROFF(c->data, c->size, uint8_t); + size_t bytes; + uint8_t data[256]; + + if (c->pos + c->size <= f->pos) + return 0; + + bytes = c->size + c->pos - f->pos; + while (bytes > 0) { + size_t s = fread(data, 1, SPA_MIN(bytes, sizeof(data)), f->file); + if (s == 0) + break; + f->pos += s; + bytes -= s; + } return 0; } @@ -86,22 +105,26 @@ static int read_PROP(struct dff_file *f, struct dff_chunk *prop) { struct dff_chunk c[1]; int res; + uint8_t data[4]; - if (f_avail(f) < 4 || - memcmp(prop->data, "SND ", 4) != 0) + if (f_read(f, data, sizeof(data)) < 0 || + memcmp(data, "SND ", 4) != 0) return -EINVAL; - f->p += 4; - while (f->p < SPA_PTROFF(prop->data, prop->size, uint8_t)) { + while (f->pos < prop->pos + prop->size) { if ((res = read_chunk(f, &c[0])) < 0) return res; switch (c[0].id) { case FOURCC('F', 'S', ' ', ' '): - f->info.rate = parse_be32(f->p); + if (f_read(f, data, 4) < 0) + return -EINVAL; + f->info.rate = parse_be32(data); break; case FOURCC('C', 'H', 'N', 'L'): - f->info.channels = parse_be16(f->p); + if (f_read(f, data, 2) < 0) + return -EINVAL; + f->info.channels = parse_be16(data); switch (f->info.channels) { case 2: f->info.channel_type = 2; @@ -116,7 +139,9 @@ static int read_PROP(struct dff_file *f, struct dff_chunk *prop) break; case FOURCC('C', 'M', 'P', 'R'): { - uint32_t cmpr = parse_be32(f->p); + if (f_read(f, data, 4) < 0) + return -EINVAL; + uint32_t cmpr = parse_be32(data); if (cmpr != FOURCC('D', 'S', 'D', ' ')) return -ENOTSUP; break; @@ -138,15 +163,16 @@ static int read_FRM8(struct dff_file *f) struct dff_chunk c[2]; int res; bool found_dsd = false; + uint8_t data[4]; if ((res = read_chunk(f, &c[0])) < 0) return res; if (c[0].id != FOURCC('F','R','M','8')) return -EINVAL; - if (f_avail(f) < 4 || - memcmp(c[0].data, "DSD ", 4) != 0) + + if (f_read(f, data, sizeof(data)) < 0 || + memcmp(data, "DSD ", 4) != 0) return -EINVAL; - f->p += 4; while (true) { if ((res = read_chunk(f, &c[1])) < 0) @@ -181,37 +207,33 @@ static int read_FRM8(struct dff_file *f) static int open_read(struct dff_file *f, const char *filename, struct dff_file_info *info) { int res; - struct stat st; - if ((f->fd = open(filename, O_RDONLY)) < 0) { - res = -errno; - goto exit; + if (strcmp(filename, "-") != 0) { + if ((f->file = fopen(filename, "r")) == NULL) { + res = -errno; + goto exit; + } + f->close = true; + } else { + f->close = false; + f->file = stdin; } - if (fstat(f->fd, &st) < 0) { - res = -errno; - goto exit_close; - } - f->size = st.st_size; - - f->data = mmap(NULL, f->size, PROT_READ, MAP_SHARED, f->fd, 0); - if (f->data == MAP_FAILED) { - res = -errno; - goto exit_close; - } - - f->p = f->data; - if ((res = read_FRM8(f)) < 0) - goto exit_unmap; + goto exit_close; + f->blocksize = BLOCKSIZE * f->info.channels; + f->buffer = calloc(1, f->blocksize); + if (f->buffer == NULL) { + res = -errno; + goto exit_close; + } f->mode = 1; *info = f->info; return 0; -exit_unmap: - munmap(f->data, f->size); exit_close: - close(f->fd); + if (f->close) + fclose(f->file); exit: return res; } @@ -267,18 +289,26 @@ dff_file_read(struct dff_file *f, void *data, size_t samples, const struct dff_l int32_t step = SPA_ABS(layout->interleave); uint32_t channels = f->info.channels; bool rev = layout->lsb != f->info.lsb; - size_t total, offset, scale; + size_t total, offset, scale, pos; offset = f->offset; + pos = offset % f->blocksize; scale = SPA_CLAMP(f->info.rate / (44100u * 64u), 1u, 4u); samples *= step; samples *= scale; - for (total = 0; total < samples && offset < f->info.length; total++) { + for (total = 0; total < samples; total++) { uint32_t i; int32_t j; - const uint8_t *s = f->p + offset; + const uint8_t *s = f->buffer + pos; + + if (pos == 0) { + if (fread(f->buffer, 1, f->blocksize, f->file) != f->blocksize) + break; + } + if (f->info.length > 0 && offset >= f->info.length) + break; for (i = 0; i < layout->channels; i++) { if (layout->interleave > 0) { @@ -294,6 +324,9 @@ dff_file_read(struct dff_file *f, void *data, size_t samples, const struct dff_l } } offset += step * channels; + pos += step * channels; + if (pos == f->blocksize) + pos = 0; } f->offset = offset; @@ -302,12 +335,9 @@ dff_file_read(struct dff_file *f, void *data, size_t samples, const struct dff_l int dff_file_close(struct dff_file *f) { - if (f->mode == 1) { - munmap(f->data, f->size); - } else - return -EINVAL; - - close(f->fd); + if (f->close) + fclose(f->file); + free(f->buffer); free(f); return 0; } diff --git a/src/tools/dsffile.c b/src/tools/dsffile.c index 213eefe26..4122944a4 100644 --- a/src/tools/dsffile.c +++ b/src/tools/dsffile.c @@ -14,16 +14,14 @@ #include "dsffile.h" struct dsf_file { - uint8_t *data; - size_t size; + uint8_t *buffer; + size_t offset; int mode; - int fd; + bool close; + FILE *file; struct dsf_file_info info; - - uint8_t *p; - size_t offset; }; static inline uint32_t parse_le32(const uint8_t *in) @@ -44,104 +42,110 @@ static inline uint64_t parse_le64(const uint8_t *in) return res; } -static inline int f_avail(struct dsf_file *f) +static inline int f_skip(struct dsf_file *f, size_t bytes) { - if (f->p < f->data + f->size) - return f->size + f->data - f->p; + uint8_t data[256]; + while (bytes > 0) { + size_t s = fread(data, 1, SPA_MIN(bytes, sizeof(data)), f->file); + bytes -= s; + } return 0; } static int read_DSD(struct dsf_file *f) { + size_t s; uint64_t size; + uint8_t data[28]; - if (f_avail(f) < 28 || - memcmp(f->p, "DSD ", 4) != 0) + s = fread(data, 1, 28, f->file); + if (s < 28 || memcmp(data, "DSD ", 4) != 0) return -EINVAL; - size = parse_le64(f->p + 4); /* size of this chunk */ - parse_le64(f->p + 12); /* total size */ - parse_le64(f->p + 20); /* metadata */ - f->p += size; + size = parse_le64(data + 4); /* size of this chunk */ + parse_le64(data + 12); /* total size */ + parse_le64(data + 20); /* metadata */ + if (size > s) + f_skip(f, size - s); return 0; } static int read_fmt(struct dsf_file *f) { + size_t s; uint64_t size; + uint8_t data[52]; - if (f_avail(f) < 52 || - memcmp(f->p, "fmt ", 4) != 0) + s = fread(data, 1, 52, f->file); + if (s < 52 || memcmp(data, "fmt ", 4) != 0) return -EINVAL; - size = parse_le64(f->p + 4); /* size of this chunk */ - if (parse_le32(f->p + 12) != 1) /* version */ + size = parse_le64(data + 4); /* size of this chunk */ + if (parse_le32(data + 12) != 1) /* version */ return -EINVAL; - if (parse_le32(f->p + 16) != 0) /* format id */ + if (parse_le32(data + 16) != 0) /* format id */ return -EINVAL; - f->info.channel_type = parse_le32(f->p + 20); - f->info.channels = parse_le32(f->p + 24); - f->info.rate = parse_le32(f->p + 28); - f->info.lsb = parse_le32(f->p + 32) == 1; - f->info.samples = parse_le64(f->p + 36); - f->info.blocksize = parse_le32(f->p + 44); - f->p += size; + f->info.channel_type = parse_le32(data + 20); + f->info.channels = parse_le32(data + 24); + f->info.rate = parse_le32(data + 28); + f->info.lsb = parse_le32(data + 32) == 1; + f->info.samples = parse_le64(data + 36); + f->info.blocksize = parse_le32(data + 44); + if (size > s) + f_skip(f, size - s); + + f->buffer = calloc(1, f->info.blocksize * f->info.channels); + if (f->buffer == NULL) + return -errno; + return 0; } static int read_data(struct dsf_file *f) { + size_t s; uint64_t size; + uint8_t data[12]; - if (f_avail(f) < 12 || - memcmp(f->p, "data", 4) != 0) + s = fread(data, 1, 12, f->file); + if (s < 12 || memcmp(data, "data", 4) != 0) return -EINVAL; - size = parse_le64(f->p + 4); /* size of this chunk */ + size = parse_le64(data + 4); /* size of this chunk */ f->info.length = size - 12; - f->p += 12; return 0; } static int open_read(struct dsf_file *f, const char *filename, struct dsf_file_info *info) { int res; - struct stat st; - if ((f->fd = open(filename, O_RDONLY)) < 0) { - res = -errno; - goto exit; + if (strcmp(filename, "-") != 0) { + if ((f->file = fopen(filename, "r")) == NULL) { + res = -errno; + goto exit; + } + f->close = true; + } else { + f->close = false; + f->file = stdin; } - if (fstat(f->fd, &st) < 0) { - res = -errno; - goto exit_close; - } - f->size = st.st_size; - - f->data = mmap(NULL, f->size, PROT_READ, MAP_SHARED, f->fd, 0); - if (f->data == MAP_FAILED) { - res = -errno; - goto exit_close; - } - - f->p = f->data; if ((res = read_DSD(f)) < 0) - goto exit_unmap; + goto exit_close; if ((res = read_fmt(f)) < 0) - goto exit_unmap; + goto exit_close; if ((res = read_data(f)) < 0) - goto exit_unmap; + goto exit_close; f->mode = 1; *info = f->info; return 0; -exit_unmap: - munmap(f->data, f->size); exit_close: - close(f->fd); + if (f->close) + fclose(f->file); exit: return res; } @@ -197,21 +201,28 @@ dsf_file_read(struct dsf_file *f, void *data, size_t samples, const struct dsf_l int step = SPA_ABS(layout->interleave); bool rev = layout->lsb != f->info.lsb; size_t total, block, offset, pos, scale; + size_t blocksize = f->info.blocksize * f->info.channels; block = f->offset / f->info.blocksize; - offset = block * f->info.blocksize * f->info.channels; + offset = block * blocksize; pos = f->offset % f->info.blocksize; scale = SPA_CLAMP(f->info.rate / (44100u * 64u), 1u, 4u); samples *= step; samples *= scale; - for (total = 0; total < samples && offset + pos < f->info.length; total++) { - const uint8_t *s = f->p + offset + pos; + for (total = 0; total < samples; total++) { uint32_t i; + if (pos == 0) { + if (fread(f->buffer, 1, blocksize, f->file) != blocksize) + break; + } + if (f->info.length > 0 && offset + pos >= f->info.length) { + break; + } for (i = 0; i < layout->channels; i++) { - const uint8_t *c = &s[f->info.blocksize * i]; + const uint8_t *c = &f->buffer[f->info.blocksize * i + pos]; int j; if (layout->interleave > 0) { @@ -225,7 +236,7 @@ dsf_file_read(struct dsf_file *f, void *data, size_t samples, const struct dsf_l pos += step; if (pos == f->info.blocksize) { pos = 0; - offset += f->info.blocksize * f->info.channels; + offset += blocksize; } } f->offset += total * step; @@ -235,12 +246,9 @@ dsf_file_read(struct dsf_file *f, void *data, size_t samples, const struct dsf_l int dsf_file_close(struct dsf_file *f) { - if (f->mode == 1) { - munmap(f->data, f->size); - } else - return -EINVAL; - - close(f->fd); + if (f->close) + fclose(f->file); + free(f->buffer); free(f); return 0; } diff --git a/src/tools/midifile.c b/src/tools/midifile.c index 482d93464..80c5bbb1c 100644 --- a/src/tools/midifile.c +++ b/src/tools/midifile.c @@ -19,27 +19,28 @@ struct midi_track { uint16_t id; - uint8_t *data; + long start; uint32_t size; + long pos; - uint8_t *p; int64_t tick; unsigned int eof:1; uint8_t event[4]; }; struct midi_file { - uint8_t *data; - size_t size; - int mode; - int fd; + FILE *file; + bool close; + long pos; + + uint8_t *buffer; + size_t buffer_size; struct midi_file_info info; uint32_t length; uint32_t tempo; - uint8_t *p; int64_t tick; double tick_sec; double tick_start; @@ -57,138 +58,157 @@ static inline uint32_t parse_be32(const uint8_t *in) return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; } -static inline int mf_avail(struct midi_file *mf) +static inline int mf_read(struct midi_file *mf, void *data, size_t size) { - if (mf->p < mf->data + mf->size) - return mf->size + mf->data - mf->p; - return 0; + if (fread(data, size, 1, mf->file) != 1) + return 0; + mf->pos += size; + return 1; } static inline int tr_avail(struct midi_track *tr) { if (tr->eof) return 0; - if (tr->p < tr->data + tr->size) - return tr->size + tr->data - tr->p; + if (tr->size == 0) + return 1; + if (tr->pos < tr->start + tr->size) + return tr->size + tr->start - tr->pos; tr->eof = true; return 0; } static int read_mthd(struct midi_file *mf) { - if (mf_avail(mf) < 14 || - memcmp(mf->p, "MThd", 4) != 0) - return -EINVAL; - - mf->length = parse_be32(mf->p + 4); - mf->info.format = parse_be16(mf->p + 8); - mf->info.ntracks = parse_be16(mf->p + 10); - mf->info.division = parse_be16(mf->p + 12); - - mf->p += 14; - return 0; -} - -static int read_mtrk(struct midi_file *mf, struct midi_track *track) -{ - if (mf_avail(mf) < 8 || - memcmp(mf->p, "MTrk", 4) != 0) - return -EINVAL; - - track->data = track->p = mf->p + 8; - track->size = parse_be32(mf->p + 4); - - mf->p = track->data + track->size; - if (mf->p > mf->data + mf->size) + uint8_t data[14]; + + if (mf_read(mf, data, sizeof(data)) != 1 || + memcmp(data, "MThd", 4) != 0) return -EINVAL; + mf->length = parse_be32(data + 4); + mf->info.format = parse_be16(data + 8); + mf->info.ntracks = parse_be16(data + 10); + mf->info.division = parse_be16(data + 12); return 0; } static int parse_varlen(struct midi_file *mf, struct midi_track *tr, uint32_t *result) { uint32_t value = 0; + uint8_t data[1]; - while (tr_avail(tr) > 0) { - uint8_t b = *tr->p++; - value = (value << 7) | (b & 0x7f); - if ((b & 0x80) == 0) + while (mf_read(mf, data, 1) == 1) { + value = (value << 7) | (data[0] & 0x7f); + if ((data[0] & 0x80) == 0) break; } *result = value; return 0; } +static int read_delta_time(struct midi_file *mf, struct midi_track *tr) +{ + int res; + uint32_t delta_time; + + if ((res = parse_varlen(mf, tr, &delta_time)) < 0) + return res; + + tr->tick += delta_time; + tr->pos = mf->pos; + return 0; + +} + +static int read_mtrk(struct midi_file *mf, struct midi_track *track) +{ + uint8_t data[8]; + + if (mf_read(mf, data, sizeof(data)) != 1 || + memcmp(data, "MTrk", 4) != 0) + return -EINVAL; + + track->start = track->pos = mf->pos; + track->size = parse_be32(data + 4); + + return read_delta_time(mf, track); +} + +static uint8_t *ensure_buffer(struct midi_file *mf, struct midi_track *tr, size_t size) +{ + if (size <= 4) + return tr->event; + + if (size > mf->buffer_size) { + mf->buffer = realloc(mf->buffer, size); + mf->buffer_size = size; + } + return mf->buffer; +} + static int open_read(struct midi_file *mf, const char *filename, struct midi_file_info *info) { int res; uint16_t i; - struct stat st; - if ((mf->fd = open(filename, O_RDONLY)) < 0) { - res = -errno; - goto exit; + if (strcmp(filename, "-") != 0) { + if ((mf->file = fopen(filename, "r")) == NULL) { + res = -errno; + goto exit; + } + mf->close = true; + } else { + mf->file = stdin; + mf->close = false; } - if (fstat(mf->fd, &st) < 0) { - res = -errno; - goto exit_close; - } - mf->size = st.st_size; - - mf->data = mmap(NULL, mf->size, PROT_READ, MAP_SHARED, mf->fd, 0); - if (mf->data == MAP_FAILED) { - res = -errno; - goto exit_close; - } - - mf->p = mf->data; if ((res = read_mthd(mf)) < 0) - goto exit_unmap; + goto exit_close; mf->tempo = DEFAULT_TEMPO; mf->tick = 0; for (i = 0; i < mf->info.ntracks; i++) { struct midi_track *tr = &mf->tracks[i]; - uint32_t delta_time; if ((res = read_mtrk(mf, tr)) < 0) - goto exit_unmap; + goto exit_close; - if ((res = parse_varlen(mf, tr, &delta_time)) < 0) - goto exit_unmap; - - tr->tick = delta_time; tr->id = i; + + if (i + 1 < mf->info.ntracks && + fseek(mf->file, tr->start + tr->size, SEEK_SET) != 0) { + res = -errno; + goto exit_close; + } } mf->mode = 1; *info = mf->info; return 0; -exit_unmap: - munmap(mf->data, mf->size); exit_close: - close(mf->fd); + if (mf->close) + fclose(mf->file); exit: return res; } -static inline int write_n(int fd, const void *buf, int count) +static inline int write_n(FILE *file, const void *buf, int count) { - return write(fd, buf, count) == (ssize_t)count ? count : -errno; + return fwrite(buf, 1, count, file) == (size_t)count ? count : -errno; } -static inline int write_be16(int fd, uint16_t val) +static inline int write_be16(FILE *file, uint16_t val) { uint8_t buf[2] = { val >> 8, val }; - return write_n(fd, buf, 2); + return write_n(file, buf, 2); } -static inline int write_be32(int fd, uint32_t val) +static inline int write_be32(FILE *file, uint32_t val) { uint8_t buf[4] = { val >> 24, val >> 16, val >> 8, val }; - return write_n(fd, buf, 4); + return write_n(file, buf, 4); } #define CHECK_RES(expr) if ((res = (expr)) < 0) return res @@ -198,17 +218,17 @@ static int write_headers(struct midi_file *mf) struct midi_track *tr = &mf->tracks[0]; int res; - lseek(mf->fd, 0, SEEK_SET); + fseek(mf->file, 0, SEEK_SET); mf->length = 6; - CHECK_RES(write_n(mf->fd, "MThd", 4)); - CHECK_RES(write_be32(mf->fd, mf->length)); - CHECK_RES(write_be16(mf->fd, mf->info.format)); - CHECK_RES(write_be16(mf->fd, mf->info.ntracks)); - CHECK_RES(write_be16(mf->fd, mf->info.division)); + CHECK_RES(write_n(mf->file, "MThd", 4)); + CHECK_RES(write_be32(mf->file, mf->length)); + CHECK_RES(write_be16(mf->file, mf->info.format)); + CHECK_RES(write_be16(mf->file, mf->info.ntracks)); + CHECK_RES(write_be16(mf->file, mf->info.division)); - CHECK_RES(write_n(mf->fd, "MTrk", 4)); - CHECK_RES(write_be32(mf->fd, tr->size)); + CHECK_RES(write_n(mf->file, "MTrk", 4)); + CHECK_RES(write_be32(mf->file, tr->size)); return 0; } @@ -226,9 +246,15 @@ static int open_write(struct midi_file *mf, const char *filename, struct midi_fi if (info->division == 0) info->division = 96; - if ((mf->fd = open(filename, O_WRONLY | O_CREAT, 0660)) < 0) { - res = -errno; - goto exit; + if (strcmp(filename, "-") != 0) { + if ((mf->file = fopen(filename, "w")) == NULL) { + res = -errno; + goto exit; + } + mf->close = true; + } else { + mf->file = stdout; + mf->close = false; } mf->mode = 2; mf->tempo = DEFAULT_TEMPO; @@ -271,17 +297,17 @@ int midi_file_close(struct midi_file *mf) { int res; - if (mf->mode == 1) { - munmap(mf->data, mf->size); - } else if (mf->mode == 2) { + if (mf->mode == 2) { uint8_t buf[4] = { 0x00, 0xff, 0x2f, 0x00 }; - CHECK_RES(write_n(mf->fd, buf, 4)); + CHECK_RES(write_n(mf->file, buf, 4)); mf->tracks[0].size += 4; CHECK_RES(write_headers(mf)); } else return -EINVAL; - close(mf->fd); + if (mf->close) + fclose(mf->file); + free(mf->buffer); free(mf); return 0; } @@ -322,22 +348,31 @@ int midi_file_next_time(struct midi_file *mf, double *sec) int midi_file_read_event(struct midi_file *mf, struct midi_event *event) { struct midi_track *tr; - uint32_t delta_time, size; + uint32_t size; uint8_t status, meta; int res, running; + long offs; + + event->data = NULL; if ((res = peek_next(mf, event)) <= 0) return res; tr = &mf->tracks[event->track]; - status = *tr->p; + + offs = tr->pos; + if (offs != mf->pos) { + if (fseek(mf->file, offs, SEEK_SET) != 0) + return -errno; + } + + mf_read(mf, &status, 1); running = (status & 0x80) == 0; if (running) { + tr->event[1] = status; status = tr->event[0]; - event->data = tr->event; } else { - event->data = tr->p++; tr->event[0] = status; } @@ -352,52 +387,82 @@ int midi_file_read_event(struct midi_file *mf, struct midi_event *event) break; case 0xff: - meta = *tr->p++; + if (running) + return -EINVAL; + + mf_read(mf, &meta, 1); if ((res = parse_varlen(mf, tr, &size)) < 0) return res; - event->meta.offset = tr->p - event->data; + event->meta.offset = 2; event->meta.size = size; + if ((event->data = ensure_buffer(mf, tr, size + event->meta.offset)) == NULL) + return -ENOMEM; + + event->data[0] = status; + event->data[1] = meta; + if (size > 0 && mf_read(mf, &event->data[2], size) != 1) + return -EINVAL; + switch (meta) { case 0x2f: tr->eof = true; break; case 0x51: + { if (size < 3) return -EINVAL; mf->tick_sec = event->sec; mf->tick_start = tr->tick; - event->meta.parsed.tempo.uspqn = mf->tempo = (tr->p[0]<<16) | (tr->p[1]<<8) | tr->p[2]; + event->meta.parsed.tempo.uspqn = mf->tempo = + (event->data[2]<<16) | (event->data[3]<<8) | event->data[4]; break; } - size += tr->p - event->data; + } + size += event->meta.offset; break; case 0xf0: case 0xf7: + if (running) + return -EINVAL; + if ((res = parse_varlen(mf, tr, &size)) < 0) return res; - size += tr->p - event->data; + + if ((event->data = ensure_buffer(mf, tr, size + 1)) == NULL) + return -ENOMEM; + + event->data[0] = status; + if (mf_read(mf, &event->data[1], size) != 1) + return -EINVAL; + + size += 1; break; default: return -EINVAL; } event->size = size; - - if (running) { - memcpy(&event->data[1], tr->p, size - 1); - tr->p += size - 1; - } else { - tr->p = event->data + event->size; + if (event->data == NULL) { + if ((event->data = ensure_buffer(mf, tr, size)) == NULL) + return -ENOMEM; + event->data[0] = tr->event[0]; + if (running) { + event->data[1] = tr->event[1]; + if (size > 2 && mf_read(mf, &event->data[2], size - 2) != 1) + return -EINVAL; + } else { + if (size > 1 && mf_read(mf, &event->data[1], size - 1) != 1) + return -EINVAL; + } } - if ((res = parse_varlen(mf, tr, &delta_time)) < 0) + if ((res = read_delta_time(mf, tr)) < 0) return res; - tr->tick += delta_time; return 1; } @@ -414,7 +479,7 @@ static int write_varlen(struct midi_file *mf, struct midi_track *tr, uint32_t va } do { b = buffer & 0xff; - CHECK_RES(write_n(mf->fd, &b, 1)); + CHECK_RES(write_n(mf->file, &b, 1)); tr->size++; buffer >>= 8; } while (b & 0x80); @@ -458,7 +523,7 @@ int midi_file_write_event(struct midi_file *mf, const struct midi_event *event) CHECK_RES(write_varlen(mf, tr, tick - tr->tick)); tr->tick = tick; - CHECK_RES(write_n(mf->fd, data, size)); + CHECK_RES(write_n(mf->file, data, size)); tr->size += size; return 0; diff --git a/src/tools/pw-cat.c b/src/tools/pw-cat.c index a1c44f802..b2ae74300 100644 --- a/src/tools/pw-cat.c +++ b/src/tools/pw-cat.c @@ -103,6 +103,7 @@ struct data { #define TYPE_ENCODED 3 #endif int data_type; + bool raw; const char *remote_name; const char *media_type; const char *media_category; @@ -980,6 +981,7 @@ static const struct option long_options[] = { { "format", required_argument, NULL, OPT_FORMAT }, { "volume", required_argument, NULL, OPT_VOLUME }, { "quality", required_argument, NULL, 'q' }, + { "raw", no_argument, NULL, 'a' }, { NULL, 0, NULL, 0 } }; @@ -1024,6 +1026,7 @@ static void show_usage(const char *name, bool is_error) " --format Sample format %s (req. for rec) (default %s)\n" " --volume Stream volume 0-1.0 (default %.3f)\n" " -q --quality Resampler quality (0 - 15) (default %d)\n" + " -a, --raw RAW mode\n" "\n"), DEFAULT_RATE, DEFAULT_CHANNELS, @@ -1691,9 +1694,9 @@ int main(int argc, char *argv[]) } #ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION - while ((c = getopt_long(argc, argv, "hvprmdoR:q:P:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hvprmdoR:q:P:a", long_options, NULL)) != -1) { #else - while ((c = getopt_long(argc, argv, "hvprmdR:q:P:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hvprmdR:q:P:a", long_options, NULL)) != -1) { #endif switch (c) { @@ -1745,6 +1748,10 @@ int main(int argc, char *argv[]) data.quality = atoi(optarg); break; + case 'a': + data.raw = true; + break; + case OPT_MEDIA_TYPE: data.media_type = optarg; break; @@ -1893,7 +1900,7 @@ int main(int argc, char *argv[]) } pw_core_add_listener(data.core, &data.core_listener, &core_events, &data); - if (spa_streq(data.filename, "-")) { + if (data.raw) { ret = setup_pipe(&data); } else { switch (data.data_type) {