dxd - dynax driver framework 3.0.1d223
cross platform open source driver development framework
Loading...
Searching...
No Matches
dx::usb::midi< buffer_t > Struct Template Reference

USB MIDI packetizer. More...

#include <dx_usb_audio.h>

Inheritance diagram for dx::usb::midi< buffer_t >:
Collaboration diagram for dx::usb::midi< buffer_t >:

Classes

union  msg
 USB MIDI endpoint element types: defining the element size for a single USB MIDI pipe request. More...

Public Member Functions

void clear (uint64_t position, uint64_t bytes)
 zero a just-consumed region, wrapping around - only safe for a single reader's own rx, never a shared/multi-reader position
size_t decode (volatile uint64_t &rx, uint8_t *dst, uint8_t cable)
 the next message of the cable as MIDI 1.0 bytes into dst, which holds 8, their count returned - 0: none
size_t decode (volatile uint64_t &rx, union msg &msg, uint8_t cable)
 USB MIDI msg word to OS MIDI stream format decoder.
uint64_t empty () const
uint64_t empty (uint64_t position) const
bool encode (const uint8_t *os_midi_package, size_t length, uint8_t cable)
 OS MIDI stream to USB MIDI msg word format encoder.
template<non_pointer ext_t, typename circular_t = ext_t>
bool force_read (ext_t *const *dst, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t channels_dst=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<non_pointer ext_t, typename circular_t = ext_t>
bool force_read (ext_t *dst, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<typename ext_t, typename circular_t = ext_t>
bool force_read (volatile uint64_t &position, ext_t *const *dst, uint64_t bulk, uint32_t channels_circular=1, uint32_t channels_dst=1, uint32_t circular_offset=0, uint32_t interleaved=1)
 multi channel interleaved bulk read from circular buffer with format conversion if applicable
template<non_pointer ext_t, typename circular_t = ext_t>
bool force_read (volatile uint64_t &position, ext_t *dst, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<typename ext_t, typename circular_t = ext_t>
bool force_write (const ext_t *const *src, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t channels_src=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<non_pointer ext_t, typename circular_t = ext_t>
bool force_write (const ext_t *src, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<typename data_t>
bool force_write (data_t *const *const *src, uint64_t clients, uint64_t channels, uint64_t bulk)
template<typename circular_t, typename src_t>
bool force_write (src_t *const *const *src, uint32_t clients, uint32_t channels=1, uint64_t bulk=1)
 multi channel multi client bulk mix into circular buffer with format conversion if applicable src[client][channel][sample]
template<typename ext_t, typename circular_t = ext_t>
bool force_write (volatile uint64_t &position, const ext_t *const *src, uint64_t bulk, uint32_t channels_circular=1, uint32_t channels_src=1, uint32_t circular_offset=0, uint32_t interleaved=1)
 multi channel interleaved bulk write into circular buffer with format conversion if applicable
template<non_pointer ext_t, typename circular_t = ext_t>
bool force_write (volatile uint64_t &position, const ext_t *src, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t circular_offset=0, uint32_t interleaved=1)
 single channel convenience access templates
void initialize ()
void initialize (uint64_t backingstore_size)
uint64_t loop () const
template<typename ext_t, typename circular_t = ext_t>
bool mix_write (volatile uint64_t &position, const ext_t *const *src, uint64_t bulk, uint32_t channels_circular=1, uint32_t channels_src=1, uint32_t circular_offset=0, uint32_t interleaved=1)
 multi channel interleaved bulk mix into circular buffer at position with format conversion if applicable
template<typename callback_t>
bool move (callback_t &callback, uint64_t packet)
template<non_pointer data_t>
bool operator<< (const data_t &src)
template<non_pointer data_t>
bool operator>> (data_t &dst)
template<auto op, typename ext_t, typename circular_t>
void put (uint64_t position, const ext_t *const *src, uint64_t bulk, uint32_t channels_circular, uint32_t channels_src, uint32_t circular_offset, uint32_t interleaved, uint64_t src_offset=0)
 multi channel interleaved bulk placement into circular space at position with wrap-around; channel operation (copy/add) selected at compile time
template<non_pointer ext_t, typename circular_t = ext_t>
bool read (ext_t *const *dst, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t channels_dst=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<non_pointer ext_t, typename circular_t = ext_t>
bool read (ext_t *dst, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<non_pointer ext_t, typename circular_t = ext_t>
bool read (volatile uint64_t &position, ext_t *const *dst, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t channels_dst=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<non_pointer ext_t, typename circular_t = ext_t>
bool read (volatile uint64_t &position, ext_t *dst, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t circular_offset=0, uint32_t interleaved=1)
void reset (int64_t timestamp)
 a session start: the indices at the ring's size, the content silence, the time the transport's
template<typename dst_t = uint8_t>
dst_t * simulate_read (uint64_t bulk=1)
template<typename dst_t = uint8_t>
dst_t * simulate_read (volatile uint64_t &position, uint64_t bulk)
uint8_t * simulate_write (uint64_t bulk)
 simulate write by advancing write idx and take care of wrap write optimization
uint64_t used () const
uint64_t used (uint64_t position) const
template<typename ext_t, typename circular_t = ext_t>
bool write (const ext_t *const *src, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t channels_src=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<non_pointer ext_t, typename circular_t = ext_t>
bool write (const ext_t *src, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t circular_offset=0, uint32_t interleaved=1)
template<typename ext_t, typename circular_t = ext_t>
bool write (volatile uint64_t &position, const ext_t *const *src, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t channels_src=1, uint32_t circular_offset=0, uint32_t interleaved=1)
 bulk write into circular buffer with format conversion if applicable
template<non_pointer ext_t, typename circular_t = ext_t>
bool write (volatile uint64_t &position, const ext_t *src, uint64_t bulk=1, uint32_t channels_circular=1, uint32_t circular_offset=0, uint32_t interleaved=1)

Static Public Member Functions

template<typename position_t>
static position_t advance (volatile position_t &position, position_t value)
 lock-free max-publish; returns the position advanced from (>= value when nothing was advanced), so the winning caller alone owns the span [returned, value)
template<typename dst_t>
static void atomic_add (dst_t *dst, int64_t added)
 atomic clip-add of one sample: concurrent writers into the same mix target must never plain read-modify-write
template<typename position_t>
static position_t exchange (volatile position_t &position, position_t comperator, position_t value)
 lock-free monotonic publish: advance position to value unless already beyond

Public Attributes

struct  cycle
uint8_t data [1]
volatile uint64_t dropout
 dropout counter
volatile uint64_t rx
 the reader side's index: a transport reader's own; every client reads at its own cursor (dx::stream::cursor)
uint64_t size
 size of buffer in bytes
volatile int64_t timestamp
 current rx/tx timestamp
volatile uint64_t tx
 producers current write index

Detailed Description

template<class buffer_t = dx::circular>
struct dx::usb::midi< buffer_t >

USB MIDI packetizer.

Member Function Documentation

◆ advance()

template<typename position_t>
position_t dx::circular::advance ( volatile position_t & position,
position_t value )
inlinestaticinherited

lock-free max-publish; returns the position advanced from (>= value when nothing was advanced), so the winning caller alone owns the span [returned, value)

Here is the call graph for this function:
Here is the caller graph for this function:

◆ atomic_add()

template<typename dst_t>
void dx::circular::atomic_add ( dst_t * dst,
int64_t added )
inlinestaticinherited

atomic clip-add of one sample: concurrent writers into the same mix target must never plain read-modify-write

Todo
packed 24bit: no lock-free CAS on a 3-byte element - plain clip-add, not yet atomic (like the floating-point formats)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear()

void dx::circular::clear ( uint64_t position,
uint64_t bytes )
inlineinherited

zero a just-consumed region, wrapping around - only safe for a single reader's own rx, never a shared/multi-reader position

Here is the caller graph for this function:

◆ decode() [1/2]

template<class buffer_t = dx::circular>
size_t dx::usb::midi< buffer_t >::decode ( volatile uint64_t & rx,
uint8_t * dst,
uint8_t cable )
inline

the next message of the cable as MIDI 1.0 bytes into dst, which holds 8, their count returned - 0: none

Here is the call graph for this function:

◆ decode() [2/2]

template<class buffer_t = dx::circular>
size_t dx::usb::midi< buffer_t >::decode ( volatile uint64_t & rx,
union msg & msg,
uint8_t cable )
inline

USB MIDI msg word to OS MIDI stream format decoder.

Pops a corresponding MIDI msg from the backing store

filters MIDI data only for this cable number and ignores: CIN misc function, future use & cable events,

generates event size out of USB-MIDI CIN (code index) classification look-up table,

Parameters
cableUSB MIDI cable number
Here is the call graph for this function:
Here is the caller graph for this function:

◆ empty() [1/2]

uint64_t dx::circular::empty ( ) const
inlineinherited
Here is the call graph for this function:
Here is the caller graph for this function:

◆ empty() [2/2]

uint64_t dx::circular::empty ( uint64_t position) const
inlineinherited
Here is the call graph for this function:

◆ encode()

template<class buffer_t = dx::circular>
bool dx::usb::midi< buffer_t >::encode ( const uint8_t * os_midi_package,
size_t length,
uint8_t cable )
inline

OS MIDI stream to USB MIDI msg word format encoder.

Encodes USB midi message from OS MIDI package and pushes it to USB MIDI backingstore buffer. It does not signal the buffer though so encode can be called for multiple MIDI packages and then manually signalled together. Although generally unusual handles SYSEX midi and any combination of general MIDI and SYSEX in the same OS package.

checks OS MIDI msg type validy,

handles SYSEX data

Todo
cleanup issue with stl not available in kernel:

checks for sysex termination prior end of os_midi_stream

checks if USB SYSEX msg fits and pushes msg to the backingstore without signalization.

handles general USB MIDI messages

computes USB MIDI msg nibbles,

checks OS MIDI msg size,

selects MIDI cable number and synthesize USB MIDI msg word,

checks if USB MIDI msg fits and pushes msg to the backingstore without signalization.

Parameters
os_midi_packageOS MIDI package
lengthlength of the OS MIDI package
cableUSB MIDI cable number

◆ exchange()

template<typename position_t>
position_t dx::circular::exchange ( volatile position_t & position,
position_t comperator,
position_t value )
inlinestaticinherited

lock-free monotonic publish: advance position to value unless already beyond

compare and swap: position takes value where it held comperator; returns what it held

Here is the caller graph for this function:

◆ force_read() [1/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::force_read ( ext_t *const * dst,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t channels_dst = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ force_read() [2/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::force_read ( ext_t * dst,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ force_read() [3/4]

template<typename ext_t, typename circular_t = ext_t>
bool dx::circular::force_read ( volatile uint64_t & position,
ext_t *const * dst,
uint64_t bulk,
uint32_t channels_circular = 1,
uint32_t channels_dst = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited

multi channel interleaved bulk read from circular buffer with format conversion if applicable

return true if enough data is available in circular space

Here is the call graph for this function:
Here is the caller graph for this function:

◆ force_read() [4/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::force_read ( volatile uint64_t & position,
ext_t * dst,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ force_write() [1/6]

template<typename ext_t, typename circular_t = ext_t>
bool dx::circular::force_write ( const ext_t *const * src,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t channels_src = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ force_write() [2/6]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::force_write ( const ext_t * src,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ force_write() [3/6]

template<typename data_t>
bool dx::circular::force_write ( data_t *const *const * src,
uint64_t clients,
uint64_t channels,
uint64_t bulk )
inlineinherited
Here is the call graph for this function:

◆ force_write() [4/6]

template<typename circular_t, typename src_t>
bool dx::circular::force_write ( src_t *const *const * src,
uint32_t clients,
uint32_t channels = 1,
uint64_t bulk = 1 )
inlineinherited

multi channel multi client bulk mix into circular buffer with format conversion if applicable src[client][channel][sample]

return true if data fit into empty space

◆ force_write() [5/6]

template<typename ext_t, typename circular_t = ext_t>
bool dx::circular::force_write ( volatile uint64_t & position,
const ext_t *const * src,
uint64_t bulk,
uint32_t channels_circular = 1,
uint32_t channels_src = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited

multi channel interleaved bulk write into circular buffer with format conversion if applicable

return true if data fit into circular space false if data fit not or older data had to be overwritten

Here is the call graph for this function:
Here is the caller graph for this function:

◆ force_write() [6/6]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::force_write ( volatile uint64_t & position,
const ext_t * src,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited

single channel convenience access templates

Here is the call graph for this function:

◆ initialize() [1/2]

void dx::circular::initialize ( )
inlineinherited

◆ initialize() [2/2]

void dx::circular::initialize ( uint64_t backingstore_size)
inlineinherited
Here is the caller graph for this function:

◆ loop()

uint64_t dx::circular::loop ( ) const
inlineinherited

◆ mix_write()

template<typename ext_t, typename circular_t = ext_t>
bool dx::circular::mix_write ( volatile uint64_t & position,
const ext_t *const * src,
uint64_t bulk,
uint32_t channels_circular = 1,
uint32_t channels_src = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited

multi channel interleaved bulk mix into circular buffer at position with format conversion if applicable

concurrent writers each holding their own position share one circular and always atomically add (never overwrite) into it - the single reader (its own rx, see above) is responsible for zeroing a region once consumed, so every writer finds a clean slate regardless of write order

return true if data fit into circular space false if data fit not or older data had to be overwritten

Here is the call graph for this function:

◆ move()

template<typename callback_t>
bool dx::circular::move ( callback_t & callback,
uint64_t packet )
inlineinherited
Here is the call graph for this function:

◆ operator<<()

template<non_pointer data_t>
bool dx::circular::operator<< ( const data_t & src)
inlineinherited
Here is the call graph for this function:

◆ operator>>()

template<non_pointer data_t>
bool dx::circular::operator>> ( data_t & dst)
inlineinherited
Here is the call graph for this function:

◆ put()

template<auto op, typename ext_t, typename circular_t>
void dx::circular::put ( uint64_t position,
const ext_t *const * src,
uint64_t bulk,
uint32_t channels_circular,
uint32_t channels_src,
uint32_t circular_offset,
uint32_t interleaved,
uint64_t src_offset = 0 )
inlineinherited

multi channel interleaved bulk placement into circular space at position with wrap-around; channel operation (copy/add) selected at compile time

Here is the caller graph for this function:

◆ read() [1/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::read ( ext_t *const * dst,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t channels_dst = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ read() [2/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::read ( ext_t * dst,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ read() [3/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::read ( volatile uint64_t & position,
ext_t *const * dst,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t channels_dst = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:
Here is the caller graph for this function:

◆ read() [4/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::read ( volatile uint64_t & position,
ext_t * dst,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ reset()

void dx::circular::reset ( int64_t timestamp)
inlineinherited

a session start: the indices at the ring's size, the content silence, the time the transport's

Here is the call graph for this function:
Here is the caller graph for this function:

◆ simulate_read() [1/2]

template<typename dst_t = uint8_t>
dst_t * dx::circular::simulate_read ( uint64_t bulk = 1)
inlineinherited
Here is the call graph for this function:

◆ simulate_read() [2/2]

template<typename dst_t = uint8_t>
dst_t * dx::circular::simulate_read ( volatile uint64_t & position,
uint64_t bulk )
inlineinherited
Here is the call graph for this function:
Here is the caller graph for this function:

◆ simulate_write()

uint8_t * dx::circular::simulate_write ( uint64_t bulk)
inlineinherited

simulate write by advancing write idx and take care of wrap write optimization

◆ used() [1/2]

uint64_t dx::circular::used ( ) const
inlineinherited
Here is the call graph for this function:
Here is the caller graph for this function:

◆ used() [2/2]

uint64_t dx::circular::used ( uint64_t position) const
inlineinherited
Here is the call graph for this function:

◆ write() [1/4]

template<typename ext_t, typename circular_t = ext_t>
bool dx::circular::write ( const ext_t *const * src,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t channels_src = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ write() [2/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::write ( const ext_t * src,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

◆ write() [3/4]

template<typename ext_t, typename circular_t = ext_t>
bool dx::circular::write ( volatile uint64_t & position,
const ext_t *const * src,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t channels_src = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited

bulk write into circular buffer with format conversion if applicable

return true if data fit into empty space

Here is the call graph for this function:
Here is the caller graph for this function:

◆ write() [4/4]

template<non_pointer ext_t, typename circular_t = ext_t>
bool dx::circular::write ( volatile uint64_t & position,
const ext_t * src,
uint64_t bulk = 1,
uint32_t channels_circular = 1,
uint32_t circular_offset = 0,
uint32_t interleaved = 1 )
inlineinherited
Here is the call graph for this function:

Member Data Documentation

◆ cycle

struct dx::circular::[struct].cycle dx::circular::cycle

◆ data

uint8_t dx::circular::data[1]
inherited

◆ dropout

volatile uint64_t dx::circular::dropout
inherited

dropout counter

◆ rx

volatile uint64_t dx::circular::rx
inherited

the reader side's index: a transport reader's own; every client reads at its own cursor (dx::stream::cursor)

◆ size

uint64_t dx::circular::size
inherited

size of buffer in bytes

◆ timestamp

volatile int64_t dx::circular::timestamp
inherited

current rx/tx timestamp

◆ tx

volatile uint64_t dx::circular::tx
inherited

producers current write index


The documentation for this struct was generated from the following file:

(c) copyright 2009 dynamic acoustics e.U. generated on

a closed source license may be obtained by requesting a written permission from dynamic acoustics e.U.
however - governmental use generally and military use especially is strictly prohibited though.