diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/c-ringbuf/ringbuf.c | 354 | ||||
-rw-r--r-- | src/c-ringbuf/ringbuf.h | 245 | ||||
-rw-r--r-- | src/descriptors.c | 59 | ||||
-rw-r--r-- | src/fft.h | 11 | ||||
-rw-r--r-- | src/helper.c | 6 | ||||
-rw-r--r-- | src/init.c | 48 | ||||
-rw-r--r-- | src/libxtract.c | 2 | ||||
-rw-r--r-- | src/scalar.c | 55 | ||||
-rw-r--r-- | src/stateful.c | 93 | ||||
-rw-r--r-- | src/vector.c | 10 |
11 files changed, 846 insertions, 39 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 71f81ca..84cbb84 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,8 @@ SOURCES = libxtract.c \ window.c \ fini.c \ helper.c \ + stateful.c \ + c-ringbuf/ringbuf.c \ dywapitchtrack/dywapitchtrack.c \ $(OOURA) diff --git a/src/c-ringbuf/ringbuf.c b/src/c-ringbuf/ringbuf.c new file mode 100644 index 0000000..048a622 --- /dev/null +++ b/src/c-ringbuf/ringbuf.c @@ -0,0 +1,354 @@ +/* + * ringbuf.c - C ring buffer (FIFO) implementation. + * + * Written in 2011 by Drew Hess <dhess-src@bothan.net>. + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include "ringbuf.h" + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#include <sys/param.h> +#include <assert.h> + +/* + * The code is written for clarity, not cleverness or performance, and + * contains many assert()s to enforce invariant assumptions and catch + * bugs. Feel free to optimize the code and to remove asserts for use + * in your own projects, once you're comfortable that it functions as + * intended. + */ + +struct ringbuf_t +{ + uint8_t *buf; + uint8_t *head, *tail; + size_t size; +}; + +ringbuf_t +ringbuf_new(size_t capacity) +{ + ringbuf_t rb = malloc(sizeof(struct ringbuf_t)); + if (rb) { + + /* One byte is used for detecting the full condition. */ + rb->size = capacity + 1; + rb->buf = malloc(rb->size); + if (rb->buf) + ringbuf_reset(rb); + else { + free(rb); + return 0; + } + } + return rb; +} + +size_t +ringbuf_buffer_size(const struct ringbuf_t *rb) +{ + return rb->size; +} + +void +ringbuf_reset(ringbuf_t rb) +{ + rb->head = rb->tail = rb->buf; +} + +void +ringbuf_free(ringbuf_t *rb) +{ + assert(rb && *rb); + free((*rb)->buf); + free(*rb); + *rb = 0; +} + +size_t +ringbuf_capacity(const struct ringbuf_t *rb) +{ + return ringbuf_buffer_size(rb) - 1; +} + +/* + * Return a pointer to one-past-the-end of the ring buffer's + * contiguous buffer. You shouldn't normally need to use this function + * unless you're writing a new ringbuf_* function. + */ +static const uint8_t * +ringbuf_end(const struct ringbuf_t *rb) +{ + return rb->buf + ringbuf_buffer_size(rb); +} + +size_t +ringbuf_bytes_free(const struct ringbuf_t *rb) +{ + if (rb->head >= rb->tail) + return ringbuf_capacity(rb) - (rb->head - rb->tail); + else + return rb->tail - rb->head - 1; +} + +size_t +ringbuf_bytes_used(const struct ringbuf_t *rb) +{ + return ringbuf_capacity(rb) - ringbuf_bytes_free(rb); +} + +int +ringbuf_is_full(const struct ringbuf_t *rb) +{ + return ringbuf_bytes_free(rb) == 0; +} + +int +ringbuf_is_empty(const struct ringbuf_t *rb) +{ + return ringbuf_bytes_free(rb) == ringbuf_capacity(rb); +} + +const void * +ringbuf_tail(const struct ringbuf_t *rb) +{ + return rb->tail; +} + +const void * +ringbuf_head(const struct ringbuf_t *rb) +{ + return rb->head; +} + +/* + * Given a ring buffer rb and a pointer to a location within its + * contiguous buffer, return the a pointer to the next logical + * location in the ring buffer. + */ +static uint8_t * +ringbuf_nextp(ringbuf_t rb, const uint8_t *p) +{ + /* + * The assert guarantees the expression (++p - rb->buf) is + * non-negative; therefore, the modulus operation is safe and + * portable. + */ + assert((p >= rb->buf) && (p < ringbuf_end(rb))); + return rb->buf + ((++p - rb->buf) % ringbuf_buffer_size(rb)); +} + +size_t +ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset) +{ + const uint8_t *bufend = ringbuf_end(rb); + size_t bytes_used = ringbuf_bytes_used(rb); + if (offset >= bytes_used) + return bytes_used; + + const uint8_t *start = rb->buf + + (((rb->tail - rb->buf) + offset) % ringbuf_buffer_size(rb)); + assert(bufend > start); + size_t n = MIN(bufend - start, bytes_used - offset); + const uint8_t *found = memchr(start, c, n); + if (found) + return offset + (found - start); + else + return ringbuf_findchr(rb, c, offset + n); +} + +size_t +ringbuf_memset(ringbuf_t dst, int c, size_t len) +{ + const uint8_t *bufend = ringbuf_end(dst); + size_t nwritten = 0; + size_t count = MIN(len, ringbuf_buffer_size(dst)); + int overflow = count > ringbuf_bytes_free(dst); + + while (nwritten != count) { + + /* don't copy beyond the end of the buffer */ + assert(bufend > dst->head); + size_t n = MIN(bufend - dst->head, count - nwritten); + memset(dst->head, c, n); + dst->head += n; + nwritten += n; + + /* wrap? */ + if (dst->head == bufend) + dst->head = dst->buf; + } + + if (overflow) { + dst->tail = ringbuf_nextp(dst, dst->head); + assert(ringbuf_is_full(dst)); + } + + return nwritten; +} + +void * +ringbuf_memcpy_into(ringbuf_t dst, const void *src, size_t count) +{ + const uint8_t *u8src = src; + const uint8_t *bufend = ringbuf_end(dst); + int overflow = count > ringbuf_bytes_free(dst); + size_t nread = 0; + + while (nread != count) { + /* don't copy beyond the end of the buffer */ + assert(bufend > dst->head); + size_t n = MIN(bufend - dst->head, count - nread); + memcpy(dst->head, u8src + nread, n); + dst->head += n; + nread += n; + + /* wrap? */ + if (dst->head == bufend) + dst->head = dst->buf; + } + + if (overflow) { + dst->tail = ringbuf_nextp(dst, dst->head); + assert(ringbuf_is_full(dst)); + } + + return dst->head; +} + +ssize_t +ringbuf_read(int fd, ringbuf_t rb, size_t count) +{ + const uint8_t *bufend = ringbuf_end(rb); + size_t nfree = ringbuf_bytes_free(rb); + + /* don't write beyond the end of the buffer */ + assert(bufend > rb->head); + count = MIN(bufend - rb->head, count); + ssize_t n = read(fd, rb->head, count); + if (n > 0) { + assert(rb->head + n <= bufend); + rb->head += n; + + /* wrap? */ + if (rb->head == bufend) + rb->head = rb->buf; + + /* fix up the tail pointer if an overflow occurred */ + if (n > nfree) { + rb->tail = ringbuf_nextp(rb, rb->head); + assert(ringbuf_is_full(rb)); + } + } + + return n; +} + +void * +ringbuf_memcpy_from(void *dst, ringbuf_t src, size_t count, bool destroy) +{ + size_t bytes_used = ringbuf_bytes_used(src); + if (count > bytes_used) + return 0; + + uint8_t *u8dst = dst; + const uint8_t *bufend = ringbuf_end(src); + uint8_t *tail = src->tail; + size_t nwritten = 0; + while (nwritten != count) { + assert(bufend > src->tail); + size_t n = MIN(bufend - src->tail, count - nwritten); + memcpy(u8dst + nwritten, src->tail, n); + src->tail += n; + nwritten += n; + + /* wrap ? */ + if (src->tail == bufend) + src->tail = src->buf; + } + + if (!destroy) + { + src->tail = tail; + } + + assert(count + ringbuf_bytes_used(src) == bytes_used); + return src->tail; +} + +ssize_t +ringbuf_write(int fd, ringbuf_t rb, size_t count) +{ + size_t bytes_used = ringbuf_bytes_used(rb); + if (count > bytes_used) + return 0; + + const uint8_t *bufend = ringbuf_end(rb); + assert(bufend > rb->head); + count = MIN(bufend - rb->tail, count); + ssize_t n = write(fd, rb->tail, count); + if (n > 0) { + assert(rb->tail + n <= bufend); + rb->tail += n; + + /* wrap? */ + if (rb->tail == bufend) + rb->tail = rb->buf; + + assert(n + ringbuf_bytes_used(rb) == bytes_used); + } + + return n; +} + +void * +ringbuf_copy(ringbuf_t dst, ringbuf_t src, size_t count) +{ + size_t src_bytes_used = ringbuf_bytes_used(src); + if (count > src_bytes_used) + return 0; + int overflow = count > ringbuf_bytes_free(dst); + + const uint8_t *src_bufend = ringbuf_end(src); + const uint8_t *dst_bufend = ringbuf_end(dst); + size_t ncopied = 0; + while (ncopied != count) { + assert(src_bufend > src->tail); + size_t nsrc = MIN(src_bufend - src->tail, count - ncopied); + assert(dst_bufend > dst->head); + size_t n = MIN(dst_bufend - dst->head, nsrc); + memcpy(dst->head, src->tail, n); + src->tail += n; + dst->head += n; + ncopied += n; + + /* wrap ? */ + if (src->tail == src_bufend) + src->tail = src->buf; + if (dst->head == dst_bufend) + dst->head = dst->buf; + } + + assert(count + ringbuf_bytes_used(src) == src_bytes_used); + + if (overflow) { + dst->tail = ringbuf_nextp(dst, dst->head); + assert(ringbuf_is_full(dst)); + } + + return dst->head; +} diff --git a/src/c-ringbuf/ringbuf.h b/src/c-ringbuf/ringbuf.h new file mode 100644 index 0000000..e971317 --- /dev/null +++ b/src/c-ringbuf/ringbuf.h @@ -0,0 +1,245 @@ +#ifndef INCLUDED_RINGBUF_H +#define INCLUDED_RINGBUF_H + +/* + * ringbuf.h - C ring buffer (FIFO) interface. + * + * Written in 2011 by Drew Hess <dhess-src@bothan.net>. + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +/* + * A byte-addressable ring buffer FIFO implementation. + * + * The ring buffer's head pointer points to the starting location + * where data should be written when copying data *into* the buffer + * (e.g., with ringbuf_read). The ring buffer's tail pointer points to + * the starting location where data should be read when copying data + * *from* the buffer (e.g., with ringbuf_write). + */ + +#include <stddef.h> +#include <sys/types.h> +#include <stdbool.h> + +typedef struct ringbuf_t *ringbuf_t; + +/* + * Create a new ring buffer with the given capacity (usable + * bytes). Note that the actual internal buffer size may be one or + * more bytes larger than the usable capacity, for bookkeeping. + * + * Returns the new ring buffer object, or 0 if there's not enough + * memory to fulfill the request for the given capacity. + */ +ringbuf_t +ringbuf_new(size_t capacity); + +/* + * The size of the internal buffer, in bytes. One or more bytes may be + * unusable in order to distinguish the "buffer full" state from the + * "buffer empty" state. + * + * For the usable capacity of the ring buffer, use the + * ringbuf_capacity function. + */ +size_t +ringbuf_buffer_size(const struct ringbuf_t *rb); + +/* + * Deallocate a ring buffer, and, as a side effect, set the pointer to + * 0. + */ +void +ringbuf_free(ringbuf_t *rb); + +/* + * Reset a ring buffer to its initial state (empty). + */ +void +ringbuf_reset(ringbuf_t rb); + +/* + * The usable capacity of the ring buffer, in bytes. Note that this + * value may be less than the ring buffer's internal buffer size, as + * returned by ringbuf_buffer_size. + */ +size_t +ringbuf_capacity(const struct ringbuf_t *rb); + +/* + * The number of free/available bytes in the ring buffer. This value + * is never larger than the ring buffer's usable capacity. + */ +size_t +ringbuf_bytes_free(const struct ringbuf_t *rb); + +/* + * The number of bytes currently being used in the ring buffer. This + * value is never larger than the ring buffer's usable capacity. + */ +size_t +ringbuf_bytes_used(const struct ringbuf_t *rb); + +int +ringbuf_is_full(const struct ringbuf_t *rb); + +int +ringbuf_is_empty(const struct ringbuf_t *rb); + +/* + * Const access to the head and tail pointers of the ring buffer. + */ +const void * +ringbuf_tail(const struct ringbuf_t *rb); + +const void * +ringbuf_head(const struct ringbuf_t *rb); + +/* + * Locate the first occurrence of character c (converted to an + * unsigned char) in ring buffer rb, beginning the search at offset + * bytes from the ring buffer's tail pointer. The function returns the + * offset of the character from the ring buffer's tail pointer, if + * found. If c does not occur in the ring buffer, the function returns + * the number of bytes used in the ring buffer. + * + * Note that the offset parameter and the returned offset are logical + * offsets from the tail pointer, not necessarily linear offsets. + */ +size_t +ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset); + +/* + * Beginning at ring buffer dst's head pointer, fill the ring buffer + * with a repeating sequence of len bytes, each of value c (converted + * to an unsigned char). len can be as large as you like, but the + * function will never write more than ringbuf_buffer_size(dst) bytes + * in a single invocation, since that size will cause all bytes in the + * ring buffer to be written exactly once each. + * + * Note that if len is greater than the number of free bytes in dst, + * the ring buffer will overflow. When an overflow occurs, the state + * of the ring buffer is guaranteed to be consistent, including the + * head and tail pointers; old data will simply be overwritten in FIFO + * fashion, as needed. However, note that, if calling the function + * results in an overflow, the value of the ring buffer's tail pointer + * may be different than it was before the function was called. + * + * Returns the actual number of bytes written to dst: len, if + * len < ringbuf_buffer_size(dst), else ringbuf_buffer_size(dst). + */ +size_t +ringbuf_memset(ringbuf_t dst, int c, size_t len); + +/* + * Copy n bytes from a contiguous memory area src into the ring buffer + * dst. Returns the ring buffer's new head pointer. + * + * It is possible to copy more data from src than is available in the + * buffer; i.e., it's possible to overflow the ring buffer using this + * function. When an overflow occurs, the state of the ring buffer is + * guaranteed to be consistent, including the head and tail pointers; + * old data will simply be overwritten in FIFO fashion, as + * needed. However, note that, if calling the function results in an + * overflow, the value of the ring buffer's tail pointer may be + * different than it was before the function was called. + */ +void * +ringbuf_memcpy_into(ringbuf_t dst, const void *src, size_t count); + +/* + * This convenience function calls read(2) on the file descriptor fd, + * using the ring buffer rb as the destination buffer for the read, + * and returns the value returned by read(2). It will only call + * read(2) once, and may return a short count. + * + * It is possible to read more data from the file descriptor than is + * available in the buffer; i.e., it's possible to overflow the ring + * buffer using this function. When an overflow occurs, the state of + * the ring buffer is guaranteed to be consistent, including the head + * and tail pointers: old data will simply be overwritten in FIFO + * fashion, as needed. However, note that, if calling the function + * results in an overflow, the value of the ring buffer's tail pointer + * may be different than it was before the function was called. + */ +ssize_t +ringbuf_read(int fd, ringbuf_t rb, size_t count); + +/* + * Copy n bytes from the ring buffer src, starting from its tail + * pointer, into a contiguous memory area dst. Returns the value of + * src's tail pointer after the copy is finished. + * + * Note if the destroy flag is set to true this copy is destructive with + * respect to the ring buffer: + * the n bytes copied from the ring buffer are no longer available in + * the ring buffer after the copy is complete, and the ring buffer + * will have n more free bytes than it did before the function was + * called. + * + * This function will *not* allow the ring buffer to underflow. If + * count is greater than the number of bytes used in the ring buffer, + * no bytes are copied, and the function will return 0. + */ +void * +ringbuf_memcpy_from(void *dst, ringbuf_t src, size_t count, bool destroy); + +/* + * This convenience function calls write(2) on the file descriptor fd, + * using the ring buffer rb as the source buffer for writing (starting + * at the ring buffer's tail pointer), and returns the value returned + * by write(2). It will only call write(2) once, and may return a + * short count. + * + * Note that this copy is destructive with respect to the ring buffer: + * any bytes written from the ring buffer to the file descriptor are + * no longer available in the ring buffer after the copy is complete, + * and the ring buffer will have N more free bytes than it did before + * the function was called, where N is the value returned by the + * function (unless N is < 0, in which case an error occurred and no + * bytes were written). + * + * This function will *not* allow the ring buffer to underflow. If + * count is greater than the number of bytes used in the ring buffer, + * no bytes are written to the file descriptor, and the function will + * return 0. + */ +ssize_t +ringbuf_write(int fd, ringbuf_t rb, size_t count); + +/* + * Copy count bytes from ring buffer src, starting from its tail + * pointer, into ring buffer dst. Returns dst's new head pointer after + * the copy is finished. + * + * Note that this copy is destructive with respect to the ring buffer + * src: any bytes copied from src into dst are no longer available in + * src after the copy is complete, and src will have 'count' more free + * bytes than it did before the function was called. + * + * It is possible to copy more data from src than is available in dst; + * i.e., it's possible to overflow dst using this function. When an + * overflow occurs, the state of dst is guaranteed to be consistent, + * including the head and tail pointers; old data will simply be + * overwritten in FIFO fashion, as needed. However, note that, if + * calling the function results in an overflow, the value dst's tail + * pointer may be different than it was before the function was + * called. + * + * It is *not* possible to underflow src; if count is greater than the + * number of bytes used in src, no bytes are copied, and the function + * returns 0. + */ +void * +ringbuf_copy(ringbuf_t dst, ringbuf_t src, size_t count); + +#endif /* INCLUDED_RINGBUF_H */ diff --git a/src/descriptors.c b/src/descriptors.c index 044f3d4..2bfdd35 100644 --- a/src/descriptors.c +++ b/src/descriptors.c @@ -42,7 +42,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) f = F = XTRACT_FEATURES; - fd = malloc(XTRACT_FEATURES * sizeof(xtract_function_descriptor_t)); + fd = (xtract_function_descriptor_t*)malloc(XTRACT_FEATURES * sizeof(xtract_function_descriptor_t)); /* FIX - this file probably needs a rewrite for readability */ @@ -88,6 +88,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_F0: case XTRACT_FAILSAFE_F0: case XTRACT_WAVELET_F0: + case XTRACT_MIDICENT: *argv_min = XTRACT_SR_LOWER_LIMIT; *argv_max = XTRACT_SR_UPPER_LIMIT; *argv_def = XTRACT_SR_DEFAULT; @@ -128,7 +129,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) *(argv_min + 1) = 0.0; *(argv_max + 1) = 1.0 ; *(argv_def + 1) = .1 ; - *(argv_unit + 1) = XTRACT_NONE; + *(argv_unit + 1) = (xtract_unit_t)XTRACT_NONE; break; case XTRACT_NOISINESS: case XTRACT_SKEWNESS: @@ -139,11 +140,11 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) *argv_min = XTRACT_NONE; *argv_max = XTRACT_NONE; *argv_def = XTRACT_NONE; - *argv_unit = XTRACT_NONE; + *argv_unit = (xtract_unit_t)XTRACT_NONE; *(argv_min + 1) = XTRACT_NONE; *(argv_max + 1) = XTRACT_NONE; *(argv_def + 1) = XTRACT_NONE; - *(argv_unit + 1) = XTRACT_NONE; + *(argv_unit + 1) = (xtract_unit_t)XTRACT_NONE; break; /* argc = 4 */ case XTRACT_SPECTRUM: @@ -154,29 +155,29 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) *(argv_min + 1) = 0; *(argv_max + 1) = 3 ; *(argv_def + 1) = 0; - *(argv_unit + 1) = XTRACT_NONE; + *(argv_unit + 1) = (xtract_unit_t)XTRACT_NONE; *(argv_min + 2) = 0; *(argv_max + 2) = 1; *(argv_def + 2) = 0; - *(argv_unit + 2) = XTRACT_NONE; + *(argv_unit + 2) = (xtract_unit_t)XTRACT_NONE; *(argv_min + 3) = 0; *(argv_max + 3) = 1; *(argv_def + 3) = 0; - *(argv_unit + 3) = XTRACT_NONE; + *(argv_unit + 3) = (xtract_unit_t)XTRACT_NONE; break; case XTRACT_SUBBANDS: *argv_min = XTRACT_ANY; *argv_max = XTRACT_ANY; *argv_def = XTRACT_MEAN; - *argv_unit = XTRACT_NONE; + *argv_unit = (xtract_unit_t)XTRACT_NONE; *(argv_min + 1) = 1; *(argv_max + 1) = 16384; *(argv_def + 1) = 4; - *(argv_unit + 1) = XTRACT_NONE; + *(argv_unit + 1) = (xtract_unit_t)XTRACT_NONE; *(argv_min + 2) = 0; *(argv_max + 2) = 32; *(argv_def + 2) = 0; - *(argv_unit + 2) = XTRACT_NONE; + *(argv_unit + 2) = (xtract_unit_t)XTRACT_NONE; *(argv_min + 3) = 0; *(argv_max + 3) = XTRACT_ANY; *(argv_def + 3) = 0; @@ -190,7 +191,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) *argv_min = XTRACT_NONE; *argv_max = XTRACT_NONE; *argv_def = XTRACT_NONE; - *argv_unit = XTRACT_NONE; + *argv_unit = (xtract_unit_t)XTRACT_NONE; break; } @@ -230,6 +231,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_F0: case XTRACT_FAILSAFE_F0: case XTRACT_WAVELET_F0: + case XTRACT_MIDICENT: *argv_donor = XTRACT_ANY; break; case XTRACT_MFCC: @@ -380,6 +382,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) break; case XTRACT_ATTACK_TIME: case XTRACT_DECAY_TIME: + case XTRACT_MIDICENT: default: *data_format = XTRACT_NO_DATA; break; @@ -440,7 +443,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_LPCC: case XTRACT_WINDOWED: case XTRACT_SUBBANDS: - *data_unit = XTRACT_ANY; + *data_unit = (xtract_unit_t)XTRACT_ANY; break; case XTRACT_SPECTRAL_MEAN: case XTRACT_SPECTRAL_VARIANCE: @@ -620,6 +623,13 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) "Extract the fundamental frequency of an audio signal (wavelet method)"); strcpy(author, "Antoine Schmitt"); break; + case XTRACT_MIDICENT: + strcpy(name, "midicent"); + strcpy(p_name, "Frequency to MIDI Cent conversion"); + strcpy(desc, "Convert frequency in Hertz to Pitch in MIDI cents"); + strcpy(p_desc, "Convert frequency in Hertz to Pitch in MIDI cents"); + strcpy(author, "Jamie Bullock"); + break; case XTRACT_TONALITY: strcpy(name, "tonality"); strcpy(p_name, "Tonality"); @@ -993,6 +1003,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_F0: case XTRACT_FAILSAFE_F0: case XTRACT_WAVELET_F0: + case XTRACT_MIDICENT: case XTRACT_FLATNESS_DB: case XTRACT_TONALITY: *argc = 1; @@ -1117,6 +1128,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_F0: case XTRACT_FAILSAFE_F0: case XTRACT_WAVELET_F0: + case XTRACT_MIDICENT: case XTRACT_FLUX: case XTRACT_LNORM: case XTRACT_NONZERO_COUNT: @@ -1195,6 +1207,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_F0: case XTRACT_FAILSAFE_F0: case XTRACT_WAVELET_F0: + case XTRACT_MIDICENT: case XTRACT_NONZERO_COUNT: case XTRACT_AUTOCORRELATION: case XTRACT_AMDF: @@ -1238,7 +1251,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_LNORM: case XTRACT_NONZERO_COUNT: case XTRACT_WINDOWED: - *result_unit = XTRACT_ANY; + *result_unit = (xtract_unit_t)XTRACT_ANY; *result_min = XTRACT_ANY; *result_max = XTRACT_ANY; break; @@ -1251,7 +1264,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_TRISTIMULUS_3: case XTRACT_NOISINESS: case XTRACT_SMOOTHNESS: - *result_unit = XTRACT_NONE; + *result_unit = (xtract_unit_t)XTRACT_NONE; *result_min = XTRACT_ANY; /* FIX: need to check these */ *result_max = XTRACT_ANY; break; @@ -1270,13 +1283,17 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) *result_min = 0.0; *result_max = XTRACT_SR_UPPER_LIMIT / 2.0; break; + case XTRACT_MIDICENT: + *result_unit = XTRACT_MIDI_CENT; + *result_min = 0.0; + *result_max = 12700; case XTRACT_ZCR: *result_unit = XTRACT_HERTZ; *result_min = 0.0; *result_max = XTRACT_ANY; break; case XTRACT_ODD_EVEN_RATIO: - *result_unit = XTRACT_NONE; + *result_unit = (xtract_unit_t)XTRACT_NONE; *result_min = 0.0; *result_max = 1.0; break; @@ -1296,7 +1313,7 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_LPC: case XTRACT_LPCC: default: - *result_unit = XTRACT_UNKNOWN; + *result_unit = (xtract_unit_t)XTRACT_UNKNOWN; *result_min = XTRACT_UNKNOWN; *result_max = XTRACT_UNKNOWN; break; @@ -1319,11 +1336,11 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) case XTRACT_SUBBANDS: case XTRACT_WINDOWED: *result_format = XTRACT_ARBITRARY_SERIES; - *result_unit = XTRACT_ANY; + *result_unit = (xtract_unit_t)XTRACT_ANY; break; case XTRACT_BARK_COEFFICIENTS: *result_format = XTRACT_BARK_COEFFS; - *result_unit = XTRACT_UNKNOWN; /* FIX: check */ + *result_unit = (xtract_unit_t)XTRACT_UNKNOWN; /* FIX: check */ break; case XTRACT_PEAK_SPECTRUM: case XTRACT_SPECTRUM: @@ -1335,15 +1352,15 @@ xtract_function_descriptor_t *xtract_make_descriptors(void) break; case XTRACT_MFCC: *result_format = XTRACT_MEL_COEFFS; - *result_unit = XTRACT_UNKNOWN; /* FIX: check */ + *result_unit = (xtract_unit_t)XTRACT_UNKNOWN; /* FIX: check */ break; case XTRACT_LPC: *result_format = XTRACT_LPC_COEFFS; - *result_unit = XTRACT_UNKNOWN; + *result_unit = (xtract_unit_t)XTRACT_UNKNOWN; break; case XTRACT_LPCC: *result_format = XTRACT_LPCC_COEFFS; - *result_unit = XTRACT_UNKNOWN; + *result_unit = (xtract_unit_t)XTRACT_UNKNOWN; break; default: break; @@ -28,7 +28,16 @@ #include <config.h> #endif -#include <stdbool.h> +#ifdef _MSC_VER + #define USE_OOURA + #ifndef __cplusplus + typedef int bool; + #define false 0 + #define true 1 + #endif +#else + #include <stdbool.h> +#endif #ifdef USE_OOURA #include "ooura/fftsg.h" diff --git a/src/helper.c b/src/helper.c index 182276f..5b7155f 100644 --- a/src/helper.c +++ b/src/helper.c @@ -75,7 +75,8 @@ int xtract_features_from_subframes(const double *data, const int N, const int fe } -inline int xtract_is_denormal(double const d) +//inline int xtract_is_denormal(double const d) +int xtract_is_denormal(double const d) { if(sizeof(d) != 2 * sizeof(int)) fprintf(stderr, "libxtract: Error: xtract_is_denormal() detects inconsistent wordlength for type 'double'\n"); @@ -84,7 +85,8 @@ inline int xtract_is_denormal(double const d) return (l&0x7ff00000) == 0 && d!=0; //Check for 0 may not be necessary } -inline bool xtract_is_poweroftwo(unsigned int x) +//inline bool xtract_is_poweroftwo(unsigned int x) +bool xtract_is_poweroftwo(unsigned int x) { return ((x != 0) && !(x & (x - 1))); } @@ -43,7 +43,7 @@ #ifdef USE_OOURA void xtract_init_ooura_data(xtract_ooura_data *ooura_data, unsigned int N) { - ooura_data->ooura_ip = (int *)calloc(2 + sqrt(N), sizeof(int)); + ooura_data->ooura_ip = (int *)calloc(2 + sqrt((double)N), sizeof(int)); ooura_data->ooura_w = (double *)calloc(N * 5 / 4, sizeof(double)); ooura_data->initialised = true; } @@ -251,19 +251,53 @@ int xtract_init_mfcc(int N, double nyquist, int style, double freq_min, double f fft_peak = NULL; norm = 1; + if (freq_bands <= 1) + { + return XTRACT_ARGUMENT_ERROR; + } + mel_freq_max = 1127 * log(1 + freq_max / 700); mel_freq_min = 1127 * log(1 + freq_min / 700); freq_bw_mel = (mel_freq_max - mel_freq_min) / freq_bands; mel_peak = (double *)malloc((freq_bands + 2) * sizeof(double)); /* +2 for zeros at start and end */ + + if (mel_peak == NULL) + { + perror("error"); + return XTRACT_MALLOC_FAILED; + } + lin_peak = (double *)malloc((freq_bands + 2) * sizeof(double)); + + if (lin_peak == NULL) + { + perror("error"); + free(mel_peak); + return XTRACT_MALLOC_FAILED; + } + fft_peak = (int *)malloc((freq_bands + 2) * sizeof(int)); + + if (fft_peak == NULL) + { + perror("error"); + free(mel_peak); + free(lin_peak); + return XTRACT_MALLOC_FAILED; + } + height_norm = (double *)malloc(freq_bands * sizeof(double)); - - if(mel_peak == NULL || height_norm == NULL || - lin_peak == NULL || fft_peak == NULL) + + if (height_norm == NULL) + { + perror("error"); + free(mel_peak); + free(lin_peak); + free(fft_peak); return XTRACT_MALLOC_FAILED; + } M = N >> 1; @@ -272,7 +306,7 @@ int xtract_init_mfcc(int N, double nyquist, int style, double freq_min, double f fft_peak[0] = lin_peak[0] / nyquist * M; - for (n = 1; n < freq_bands + 2; n++) + for (n = 1; n < (freq_bands + 2); ++n) { //roll out peak locations - mel, linear and linear on fft window scale mel_peak[n] = mel_peak[n - 1] + freq_bw_mel; @@ -363,7 +397,7 @@ double *xtract_init_window(const int N, const int type) { double *window; - window = malloc(N * sizeof(double)); + window = (double*)malloc(N * sizeof(double)); switch (type) { @@ -410,7 +444,7 @@ void xtract_free_window(double *window) #ifdef __GNUC__ __attribute__((constructor)) void init() #else -void _init()ยท +void _init() #endif { #ifdef USE_OOURA diff --git a/src/libxtract.c b/src/libxtract.c index 99162fb..624e8cd 100644 --- a/src/libxtract.c +++ b/src/libxtract.c @@ -36,7 +36,6 @@ int(*xtract[])(const double *, const int, const void *, double *) = xtract_spectral_mean, xtract_spectral_variance, xtract_spectral_standard_deviation, - /* xtract_spectral_average_deviation, */ xtract_spectral_skewness, xtract_spectral_kurtosis, xtract_spectral_centroid, @@ -69,6 +68,7 @@ int(*xtract[])(const double *, const int, const void *, double *) = xtract_f0, xtract_failsafe_f0, xtract_wavelet_f0, + xtract_midicent, /* xtract_delta.h */ xtract_lnorm, xtract_flux, diff --git a/src/scalar.c b/src/scalar.c index becf341..74d6cee 100644 --- a/src/scalar.c +++ b/src/scalar.c @@ -889,8 +889,8 @@ int xtract_f0(const double *data, const int N, const void *argv, double *result) if(sr == 0) sr = 44100.0; - input = (double *)malloc(bytes = N * sizeof(double)); - input = memcpy(input, data, bytes); + input = (double*)malloc(bytes = N * sizeof(double)); + input = (double*)memcpy(input, data, bytes); /* threshold_peak = *((double *)argv+1); threshold_centre = *((double *)argv+2); printf("peak: %.2\tcentre: %.2\n", threshold_peak, threshold_centre);*/ @@ -1000,4 +1000,55 @@ int xtract_wavelet_f0(const double *data, const int N, const void *argv, double return XTRACT_SUCCESS; } +int xtract_midicent(const double *data, const int N, const void *argv, double *result) +{ + double f0 = *(double *)argv; + double note = 0.0; + + note = 69 + log(f0 / 440.f) * 17.31234; + note *= 100; + note = floor( 0.5f + note ); // replace -> round(note); + + *result = note; + + if (note > 12700 || note < 0) + { + return XTRACT_ARGUMENT_ERROR; + } + + return XTRACT_SUCCESS; +} + +int xtract_peak(const double *data, const int N, const void *argv, double *result) +{ + double threshold = *(double *)argv; + double current = data[N - 1]; + double average = 0.0; + double maximum = -DBL_MAX; + + for (uint32_t n = 0; n < N; ++n) + { + average += data[n]; + if (data[n] > maximum) + { + maximum = data[n]; + } + } + + average /= (double)N; + + if (current != maximum) + { + return XTRACT_NO_RESULT; + } + + if (current < average + threshold) + { + return XTRACT_NO_RESULT; + } + + return XTRACT_SUCCESS; + +} + diff --git a/src/stateful.c b/src/stateful.c new file mode 100644 index 0000000..501db45 --- /dev/null +++ b/src/stateful.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012 Jamie Bullock + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +/* stateful.c: declares functions that extract features that require stateful data to be retained between frames */ + +#include "../xtract/xtract_stateful.h" +#include "../xtract/libxtract.h" + +#include "c-ringbuf/ringbuf.h" + +#include <stdlib.h> +#include <stdio.h> +#include <float.h> + +struct xtract_last_n_state_ +{ + ringbuf_t ringbuf; +}; + + +xtract_last_n_state *xtract_last_n_state_new(size_t N) +{ + xtract_last_n_state *last_n_state = malloc(sizeof(xtract_last_n_state)); + + if (last_n_state == NULL) + { + perror("could not allocate memory for xtract_last_n_state"); + return NULL; + } + + last_n_state->ringbuf = ringbuf_new(N * sizeof(double)); + + if (last_n_state->ringbuf) + { + perror("could not allocate memory for xtract_last_n_state->ringbuf"); + } + + return last_n_state; +} + +void xtract_last_n_state_delete(xtract_last_n_state *last_n_state) +{ + ringbuf_free(&last_n_state->ringbuf); + free(last_n_state); +} + +int xtract_last_n(const xtract_last_n_state *state, const double *data, const int N, const void *argv, double *result) +{ + double *current = (double *)argv; + size_t N_bytes = N * sizeof(double); + + if (N_bytes != ringbuf_capacity(state->ringbuf)) + { + fprintf(stderr, "libxtract: error: xtract_last_n(): inconsitent size"); + return XTRACT_BAD_STATE; + } + + ringbuf_memcpy_into(state->ringbuf, current, sizeof(double)); + size_t used = ringbuf_bytes_used(state->ringbuf); + ringbuf_memcpy_from(result, state->ringbuf, used, false); + + if (used < N_bytes) + { + /* zero pad */ + for (size_t n = used / sizeof(double); n < N; ++n) + { + result[n] = 0.0; + } + } + + return XTRACT_SUCCESS; +} + diff --git a/src/vector.c b/src/vector.c index 5074b65..9c49c2c 100644 --- a/src/vector.c +++ b/src/vector.c @@ -83,7 +83,7 @@ int xtract_spectrum(const double *data, const int N, const void *argv, double *r * the output format is * a[0] - DC, a[1] - nyquist, a[2...N-1] - remaining bins */ - fft = malloc(N * sizeof(double)); + fft = (double*)malloc(N * sizeof(double)); assert(fft != NULL); memcpy(fft, data, N * sizeof(double)); @@ -375,7 +375,7 @@ int xtract_dct(const double *data, const int N, const void *argv, double *result int n; int m; - double *temp = calloc(N, sizeof(double)); + double *temp = (double*)calloc(N, sizeof(double)); for (n = 0; n < N; ++n) { @@ -502,7 +502,7 @@ int xtract_peak_spectrum(const double *data, const int N, const void *argv, doub bytes = N * sizeof(double); if(input != NULL) - input = memcpy(input, data, bytes); + input = (double*)memcpy(input, data, bytes); else return XTRACT_MALLOC_FAILED; @@ -562,8 +562,8 @@ int xtract_harmonic_spectrum(const double *data, const int N, const void *argv, if(freqs[n]) { ratio = freqs[n] / f0; - nearest = round(ratio); - distance = fabs(nearest - ratio); + nearest = floor( 0.5f + ratio); // replace -> nearest = round(ratio); + distance = fabs(nearest - ratio); if(distance > threshold) result[n] = result[M + n] = 0.0; else |