lfringbuffer.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #include "lfringbuffer.h"
  2. #include "foundation/error.h"
  3. #include <stdlib.h>
  4. typedef struct LFRingBufferHeader
  5. {
  6. volatile size_t used; /* number of bytes written, in elements */
  7. size_t size; /* in elements */
  8. size_t write_position;
  9. size_t read_position;
  10. } LFRingBufferHeader;
  11. typedef struct LFRingBuffer
  12. {
  13. LFRingBufferHeader header;
  14. float data[1];
  15. } LFRingBuffer;
  16. /* create a ring buffer with the desired number of elements */
  17. int lfringbuffer_create(lfringbuffer_t *out_ring_buffer, size_t number_of_elements)
  18. {
  19. LFRingBuffer *ring_buffer = (LFRingBuffer *)malloc(sizeof(LFRingBufferHeader) + sizeof(float) * number_of_elements);
  20. if (!ring_buffer)
  21. return NErr_OutOfMemory;
  22. ring_buffer->header.used = 0;
  23. ring_buffer->header.size = number_of_elements;
  24. ring_buffer->header.write_position = 0;
  25. ring_buffer->header.read_position = 0;
  26. *out_ring_buffer = (lfringbuffer_t)ring_buffer;
  27. return NErr_Success;
  28. }
  29. int lfringbuffer_destroy(lfringbuffer_t ring_buffer)
  30. {
  31. free(ring_buffer);
  32. return NErr_Success;
  33. }
  34. /* ----- Read functions ----- */
  35. /* get how many elements can currently be read */
  36. size_t lfringbuffer_read_available(lfringbuffer_t rb)
  37. {
  38. LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
  39. return ring_buffer->header.used;
  40. }
  41. /* retrieve a pointer that can be read from.
  42. you might have to call this twice, because of ring buffer wraparound
  43. call lfringbuffer_read_update() when you are done */
  44. int lfringbuffer_read_get(lfringbuffer_t rb, size_t elements_requested, const float **out_buffer, size_t *elements_available)
  45. {
  46. LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
  47. size_t end, to_copy;
  48. int ret = NErr_Success;
  49. /* can only read how many bytes we have available */
  50. to_copy=ring_buffer->header.used;
  51. if (to_copy > elements_requested)
  52. {
  53. to_copy = elements_requested;
  54. ret = NErr_Underrun; /* signal that there was a buffer underrun when reading */
  55. }
  56. /* can only read until the end of the buffer */
  57. end = ring_buffer->header.size-ring_buffer->header.read_position;
  58. if (to_copy > end)
  59. {
  60. to_copy = end;
  61. ret = NErr_TryAgain; /* signal that they need to call again to get the next part of the buffer */
  62. }
  63. *out_buffer = ring_buffer->data + ring_buffer->header.read_position;
  64. *elements_available = to_copy;
  65. ring_buffer->header.read_position += to_copy;
  66. if (ring_buffer->header.read_position == ring_buffer->header.size)
  67. ring_buffer->header.read_position=0;
  68. return ret;
  69. }
  70. /* call to acknowledge that you have read the bytes */
  71. void lfringbuffer_read_update(lfringbuffer_t rb, size_t elements_read)
  72. {
  73. LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
  74. #if defined(__ARM_ARCH_7A__)
  75. __asm__ __volatile__ ("dmb" : : : "memory");
  76. #endif
  77. nx_atomic_sub(elements_read, &ring_buffer->header.used);
  78. }
  79. static void lfringbuffer_read_set_position(lfringbuffer_t rb, size_t position)
  80. {
  81. LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
  82. intptr_t bytes_to_flush = (intptr_t)(position - (size_t)ring_buffer->header.read_position);
  83. if (bytes_to_flush < 0)
  84. bytes_to_flush += ring_buffer->header.size;
  85. lfringbuffer_read_update(rb, bytes_to_flush);
  86. }
  87. /* ----- Write functions ----- */
  88. /* get how many elements can currently be written */
  89. size_t lfringbuffer_write_available(lfringbuffer_t rb)
  90. {
  91. LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
  92. return ring_buffer->header.size - ring_buffer->header.used;
  93. }
  94. /* retrieve a pointer that can be written to.
  95. you might have to call this twice, because of ring buffer wraparound
  96. call lfringbuffer_write_update() when you are done */
  97. int lfringbuffer_write_get(lfringbuffer_t rb, size_t elements_requested, float **out_buffer, size_t *elements_available)
  98. {
  99. LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
  100. size_t end, to_copy;
  101. int ret = NErr_Success;
  102. /* can only write how many bytes we have available */
  103. to_copy=ring_buffer->header.size - ring_buffer->header.used;
  104. if (to_copy > elements_requested)
  105. {
  106. to_copy = elements_requested;
  107. ret = NErr_Underrun; /* signal that there was a buffer underrun when reading */
  108. }
  109. /* can only read until the end of the buffer */
  110. end = ring_buffer->header.size-ring_buffer->header.write_position;
  111. if (to_copy > end)
  112. {
  113. to_copy = end;
  114. ret = NErr_TryAgain; /* signal that they need to call again to get the next part of the buffer */
  115. }
  116. *out_buffer = ring_buffer->data + ring_buffer->header.write_position;
  117. *elements_available = to_copy;
  118. ring_buffer->header.write_position += to_copy;
  119. if (ring_buffer->header.write_position == ring_buffer->header.size)
  120. ring_buffer->header.write_position=0;
  121. return ret;
  122. }
  123. /* call to acknowledge that you have written the bytes */
  124. void lfringbuffer_write_update(lfringbuffer_t rb, size_t elements_read)
  125. {
  126. LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
  127. #if defined(__ARM_ARCH_7A__)
  128. __asm__ __volatile__ ("dmb" : : : "memory");
  129. #endif
  130. nx_atomic_add(elements_read, &ring_buffer->header.used);
  131. }
  132. size_t lfringbuffer_write_get_position(lfringbuffer_t rb)
  133. {
  134. LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
  135. return ring_buffer->header.write_position;
  136. }