summaryrefslogtreecommitdiff
path: root/libs/fluidsynth/src/fluid_ringbuffer.h
blob: e78d52291b059558112894bf82909990db551262 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* FluidSynth - A Software Synthesizer
 *
 * Copyright (C) 2003  Peter Hanappe and others.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA
 */

#ifndef _FLUID_RINGBUFFER_H
#define _FLUID_RINGBUFFER_H

#include "fluid_sys.h"

/*
 * Lockless event queue instance.
 */
struct _fluid_ringbuffer_t
{
    char *array;  /**< Queue array of arbitrary size elements */
    int totalcount;       /**< Total count of elements in array */
    fluid_atomic_int_t count;            /**< Current count of elements */
    int in;               /**< Index in queue to store next pushed element */
    int out;              /**< Index in queue of next popped element */
    int elementsize;          /**< Size of each element */
    void *userdata;
};

typedef struct _fluid_ringbuffer_t fluid_ringbuffer_t;


fluid_ringbuffer_t *new_fluid_ringbuffer(int count, int elementsize);
void delete_fluid_ringbuffer(fluid_ringbuffer_t *queue);

/**
 * Get pointer to next input array element in queue.
 * @param queue Lockless queue instance
 * @param offset Normally zero, or more if you need to push several items at once
 * @return Pointer to array element in queue to store data to or NULL if queue is full
 *
 * This function along with fluid_ringbuffer_next_inptr() form a queue "push"
 * operation and is split into 2 functions to avoid an element copy.  Note that
 * the returned array element pointer may contain the data of a previous element
 * if the queue has wrapped around.  This can be used to reclaim pointers to
 * allocated memory, etc.
 */
static FLUID_INLINE void *
fluid_ringbuffer_get_inptr(fluid_ringbuffer_t *queue, int offset)
{
    return fluid_atomic_int_get(&queue->count) + offset >= queue->totalcount ? NULL
           : queue->array + queue->elementsize * ((queue->in + offset) % queue->totalcount);
}

/**
 * Advance the input queue index to complete a "push" operation.
 * @param queue Lockless queue instance
 * @param count Normally one, or more if you need to push several items at once
 *
 * This function along with fluid_ringbuffer_get_inptr() form a queue "push"
 * operation and is split into 2 functions to avoid element copy.
 */
static FLUID_INLINE void
fluid_ringbuffer_next_inptr(fluid_ringbuffer_t *queue, int count)
{
    fluid_atomic_int_add(&queue->count, count);

    queue->in += count;

    if(queue->in >= queue->totalcount)
    {
        queue->in -= queue->totalcount;
    }
}

/**
 * Get amount of items currently in queue
 * @param queue Lockless queue instance
 * @return amount of items currently in queue
 */
static FLUID_INLINE int
fluid_ringbuffer_get_count(fluid_ringbuffer_t *queue)
{
    return fluid_atomic_int_get(&queue->count);
}


/**
 * Get pointer to next output array element in queue.
 * @param queue Lockless queue instance
 * @return Pointer to array element data in the queue or NULL if empty, can only
 *   be used up until fluid_ringbuffer_next_outptr() is called.
 *
 * This function along with fluid_ringbuffer_next_outptr() form a queue "pop"
 * operation and is split into 2 functions to avoid an element copy.
 */
static FLUID_INLINE void *
fluid_ringbuffer_get_outptr(fluid_ringbuffer_t *queue)
{
    return fluid_ringbuffer_get_count(queue) == 0 ? NULL
           : queue->array + queue->elementsize * queue->out;
}


/**
 * Advance the output queue index to complete a "pop" operation.
 * @param queue Lockless queue instance
 *
 * This function along with fluid_ringbuffer_get_outptr() form a queue "pop"
 * operation and is split into 2 functions to avoid an element copy.
 */
static FLUID_INLINE void
fluid_ringbuffer_next_outptr(fluid_ringbuffer_t *queue)
{
    fluid_atomic_int_add(&queue->count, -1);

    if(++queue->out == queue->totalcount)
    {
        queue->out = 0;
    }
}

#endif /* _FLUID_ringbuffer_H */