Browse Source

Add complete documentation for the MIDI modules

Complete the Doxygen comments in the midi.c, sysex.c and
microx.c modules. Also add a Doxygen settings file to
generate the documentation from these comments.
develop
Damien Goutte-Gattat 7 years ago
parent
commit
c60f5824e7
9 changed files with 2148 additions and 33 deletions
  1. +1
    -0
      .gitignore
  2. +1794
    -0
      Doxyfile
  3. +2
    -0
      Makefile.am
  4. +2
    -2
      src/kmxtool.c
  5. +151
    -22
      src/microx.c
  6. +16
    -0
      src/microx.h
  7. +117
    -8
      src/midi.c
  8. +50
    -1
      src/sysex.c
  9. +15
    -0
      src/sysex.h

+ 1
- 0
.gitignore View File

@ -9,6 +9,7 @@ config.status
config
configure
stamp-*
doc
# Autoconf macros files (ignored by default)
*.m4


+ 1794
- 0
Doxyfile
File diff suppressed because it is too large
View File


+ 2
- 0
Makefile.am View File

@ -3,3 +3,5 @@ SUBDIRS = lib src man
ACLOCAL_AMFLAGS = -I m4 --install
dist_doc_DATA = AUTHORS COPYING README
EXTRA_DIST = Doxyfile

+ 2
- 2
src/kmxtool.c View File

@ -313,7 +313,7 @@ main(int argc, char **argv)
int n;
dump.load = 0;
if ( kmx_microx_parse_dump_request(param, &dump) == -1 )
if ( kmx_microx_parse_dump_request(param, &dump) == KMX_INVALID_QUERY )
errx(EXIT_FAILURE, "invalid dump request: %s", param);
n = kmx_microx_get_dump_size(&dump);
@ -330,7 +330,7 @@ main(int argc, char **argv)
ssize_t n;
dump.load = 1;
if ( kmx_microx_parse_dump_request(param, &dump) == -1 )
if ( kmx_microx_parse_dump_request(param, &dump) == KMX_INVALID_QUERY )
errx(EXIT_FAILURE, "invalid load request: %s", param);
data = NULL;


+ 151
- 22
src/microx.c View File

@ -16,6 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file microx.c
* MicroX-specific functions.
*
* This module provides helper functions to deal with a Korg microX
* synthesizer.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@ -26,9 +33,18 @@
#include <sysex.h>
/**
* Identify a connected microX device.
* This function check whether the device connected to the MIDI
* port is a Korg microX synthesizer.
*
* @param[in] midi The MIDI port.
* @param[out] version A pointer to a kmx_microx_version structure
* to be filled in with informations from the
* device; may be @c NULL.
*
* @return
* - 0 if the port is connected to a device which successfully
* identified itself as a microX device;
* - @e KMX_OK if the port is connected to a device which
* successfully identified itself as a microX device;
* - @e KMX_IO_ERROR if an I/O error occured;
* - @e KMX_INVALID_REPLY if the device replied incorrectly:
* - @e KMX_NOT_KORG is the device did not identify itself as
@ -61,12 +77,21 @@ kmx_microx_identify(midi_io_t *midi,
version->build = (devid.version >> 24) & 0xFF;
}
return 0;
return KMX_OK;
}
/**
* Get the microX current status.
* This function gets the current status of the connected microX
* synthesizer.
*
* @param[in] midi The MIDI port.
* @param[out] status A pointer to a kmx_microx_status structure
* to be filled in with the status data
* received from the microX; may be @c NULL.
*
* @return
* - 0 if the query was successful;
* - @e KMX_OK if the query was successful;
* - @e KMX_IO_ERROR if an I/O error occured;
* - @e KMX_NOT_KORG if the reply did not come from a Korg device;
* - @e KMX_INVALID_REPLY if the device replied incorrectly.
@ -178,10 +203,21 @@ kmx_microx_query_status(midi_io_t *midi,
s->ext_ctrl.current = reply[24];
}
return 0;
return KMX_OK;
}
/**
* Get an error message.
* This function translates an error code returned by other
* functions of this module to an error message.
*
* If the error happens to be a MIDI I/O error, this function
* calls the midi_error() function to get a meaningful
* message from the underlying MIDI API.
*
* @param[in] midi The MIDI port used to talk to the microX.
* @param[in] e The error code to lookup.
*
* @return
* A static string containing the user-readable error message.
*/
@ -256,6 +292,12 @@ static struct {
};
/**
* Parse a string as a positive integer.
* This function parses the given string as a positive integer
* value.
*
* @param[in] s The string to parse.
*
* @return
* - The positive integer value contained in @a s;
* - -1 if @a s could not be parsed as a positive integer value.
@ -279,9 +321,43 @@ parse_int(const char *s)
}
/**
* Parse a string as a dump/load request to the microX.
* This function translates a string to a formal representation
* of a dump or load parameter request to a microX device.
*
* If the request string is valid and successfully parsed, the
* function fills in a kmx_microx_dump structure which may then
* be used in a call to kmx_microx_dump() or kmx_microx_load().
*
* The request string should start with a single letter
* indicating the type of memory to dump or load: 'P' for programs,
* 'C' for combinations, 'M' for multis, 'D' for drumkits,
* 'A' for arpeggio patterns, or 'E' for external controllers sets.
* It must be followed by a single uppercase letter indicating the
* bank (only for programs and combinations), and up to three
* decimal digits indicating the slot number (counting from one).
*
* An asterisk may be used instead of the program number, in that
* case the microX will be instructed to dump all slots in the
* bank. For programs and combinations, an asterisk may also be
* used instead of the bank letter @e and the program number, in
* that case the microX will be instructed to dump all slots in
* all program or combination banks.
*
* For example:
*
* - @c "PA123" means "dump program #123 of bank A";
* - @c "M17" means "dump multi #17";
* - @c "CB*" means "dump all combinations in bank B";
* - @c "C*" means "dump all combinations in all banks";
* - @c "D*" means "dump all drumkits".
*
* @param[in] what The request string to parse.
* @param[out] The kmx_microx_dump structure to fill in.
*
* @return
* - 0 if the dump request was successfully parsed.
* - -1 if the dump request is invalid.
* - @e KMX_OK if the dump request was successfully parsed.
* - @e KMX_INVALID_QUERY if the dump request is invalid.
*/
int
kmx_microx_parse_dump_request(const char *what, struct kmx_microx_dump *dump)
@ -289,7 +365,7 @@ kmx_microx_parse_dump_request(const char *what, struct kmx_microx_dump *dump)
int val, ret;
char bank;
ret = 0;
ret = KMX_OK;
switch ( *what++ ) {
case 'P':
@ -304,10 +380,10 @@ kmx_microx_parse_dump_request(const char *what, struct kmx_microx_dump *dump)
else if ( (val = parse_int(what)) >= 1 && val <= MICROX_BANK_SIZE )
dump->program = val - 1;
else
ret = -1;
ret = KMX_INVALID_QUERY;
}
else
ret = -1;
ret = KMX_INVALID_QUERY;
break;
case 'C':
@ -322,10 +398,10 @@ kmx_microx_parse_dump_request(const char *what, struct kmx_microx_dump *dump)
else if ( (val = parse_int(what)) >= 1 && val <= MICROX_BANK_SIZE )
dump->program = val - 1;
else
ret = -1;
ret = KMX_INVALID_QUERY;
}
else
ret = -1;
ret = KMX_INVALID_QUERY;
break;
case 'M':
@ -335,7 +411,7 @@ kmx_microx_parse_dump_request(const char *what, struct kmx_microx_dump *dump)
else if ( (val = parse_int(what)) >= 1 && val <= MICROX_N_MULTI )
dump->program = val - 1;
else
ret = -1;
ret = KMX_INVALID_QUERY;
break;
case 'D':
@ -345,7 +421,7 @@ kmx_microx_parse_dump_request(const char *what, struct kmx_microx_dump *dump)
else if ( (val = parse_int(what)) >= 1 && val <= MICROX_N_DRUMKIT )
dump->program = val - 1;
else
ret = -1;
ret = KMX_INVALID_QUERY;
break;
case 'A':
@ -355,7 +431,7 @@ kmx_microx_parse_dump_request(const char *what, struct kmx_microx_dump *dump)
else if ( (val = parse_int(what)) >= 1 && val <= MICROX_N_ARPEGGIO )
dump->program = val - 1;
else
ret = -1;
ret = KMX_INVALID_QUERY;
break;
case 'E':
@ -365,17 +441,25 @@ kmx_microx_parse_dump_request(const char *what, struct kmx_microx_dump *dump)
else if ( (val = parse_int(what)) >= 1 && val <= MICROX_N_EXTSET )
dump->program = val - 1;
else
ret = -1;
ret = KMX_INVALID_QUERY;
break;
default:
ret = -1;
ret = KMX_INVALID_QUERY;
}
return ret;
}
/**
* Get the size of a microX data dump.
* Given a formal dump specification as returned by the
* kmx_microx_parse_dump_request() function, this function
* returns the expected size of the corresponding dump.
*
* @param[in] dump A kmx_microx_dump structure representing
* a dump request.
*
* @return
* The expected size of the specified data dump.
*/
@ -430,9 +514,21 @@ kmx_microx_get_dump_size(struct kmx_microx_dump *dump)
}
/**
* Translate a dump request into actual MIDI bytes.
* Given a formal dump specification as returned by the
* kmx_microx_parse_dump_request() function, this function
* translates the request into the appropriate MIDI bytes
* that can be received by a microX synthesizer.
*
* @param[in] dump A kmx_microx_dump structure
* representing a dump request.
* @param[out] buffer A buffer to be filled in with the
* appropriate MIDI bytes; this buffer
* should be at least 4 four bytes long.
*
* @return
* - 0 if the operation was successful;
* - -1 if an error occured.
* - @e KMX_OK if the operation was successful;
* - @e KMX_INVALID_QUERY if an error occured.
*
* The current implementation is always successful.
*/
@ -509,10 +605,21 @@ get_dump_parameters(struct kmx_microx_dump *dump,
break;
}
return 0;
return KMX_OK;
}
/**
* Read a microX data dump.
* This function reads data from a MIDI port and, if it corresponds
* to a SysEx message announcing a Korg microX data dump, translates
* it from the MIDI encoding used to transmit it.
*
* @param[in] midi The MIDI port to read from.
* @param[in] reply_code The expected function code of the SysEx
* message to read.
* @param[out] data The buffer where to store the dump.
* @param[in] len The size of the @a data buffer.
*
* @return
* - The count of data bytes read and stored in the @a data buffer;
* - @e KMX_IO_ERROR if an I/O error occured;
@ -581,6 +688,17 @@ kmx_microx_read_dump(midi_io_t *midi,
}
/**
* Dump memory slot(s) from a microX device.
* This function sends a parameter dump request to the
* connected microX synthesizer and gets the dump data
* in reply.
*
* @param[in] midi The MIDI port.
* @param[in] dump A kmx_microx_dump structure representing
* the dump request.
* @param[out] data The buffer where to store the dump.
* @param[in] len The size of the @a data buffer.
*
* @return
* - The number of bytes read and stored in the @a data buffer;
* - @e KMX_IO_ERROR if an I/O error occured;
@ -608,7 +726,7 @@ kmx_microx_dump(midi_io_t *midi,
0x00, /* Dump parameter 3 */
0xF7 /* SysEx message end */ };
if ( get_dump_parameters(dump, &(query[4])) == -1 )
if ( get_dump_parameters(dump, &(query[4])) == KMX_INVALID_QUERY )
return KMX_INVALID_QUERY;
if ( len < kmx_microx_get_dump_size(dump) )
@ -621,6 +739,17 @@ kmx_microx_dump(midi_io_t *midi,
}
/**
* Load a memory slot to a microX device.
* This function loads the provided data to a memory slot of
* the microX synthesizer.
*
* @param[in] midi The MIDI port.
* @param[in] dump A kmx_microx_dump structure indicating the
* memory slot to load the data into.
* @param[in] data The data to load.
* @param[in] len The number of bytes from the @a data buffer
* to send to the device.
*
* @return
* - @e KMX_OK if the load operation completed successfully;
* - @e KMX_IO_ERROR if an I/O error occured;
@ -654,7 +783,7 @@ kmx_microx_load(midi_io_t *midi,
0x00, /* Dump parameter 3 */ };
unsigned char reply[7];
if ( get_dump_parameters(dump, &(buffer[4])) == -1 )
if ( get_dump_parameters(dump, &(buffer[4])) == KMX_INVALID_QUERY )
return KMX_INVALID_QUERY;
if ( len < kmx_microx_get_dump_size(dump) )


+ 16
- 0
src/microx.h View File

@ -156,11 +156,27 @@ struct kmx_microx_status
#define KMX_MICROX_DUMP_ALL -1
/** Represents a parameter dump/load request. */
struct kmx_microx_dump
{
/** The type of memory slot. */
enum kmx_microx_data_type type;
/** If non-zero, represents a load request. */
char load;
/** The bank letter.
* Represents the bank letter of a dump request
* (only for programs and combinations); if set to
* KMX_MICROX_DUMP_ALL, indicates to dump all
* programs or combinations in all banks. */
char bank;
/** The program number.
* Represents the program number (counting from
* zero); if set to KMX_MICROX_DUMP_ALL, indicates
* to dump all slots of the given type or of the
* given bank (for programs and combinations). */
short program;
};


+ 117
- 8
src/midi.c View File

@ -16,6 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file midi.c
* MIDI I/O API.
*
* This module implements an abstraction layer above the system MIDI
* I/O API(s).
*
* Currently the supported APIs are ALSA and OSS.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@ -38,31 +47,56 @@
#include <dirent.h>
#endif
/** Pointer to a backend-specific implementation of midi_close(). */
typedef int (*m_close) (midi_io_t *);
/** Pointer to a backend-specific implementation of midi_write(). */
typedef ssize_t (*m_write) (midi_io_t *, unsigned char *, size_t);
/** Pointer to a backend-specific implementation of midi_read(). */
typedef ssize_t (*m_read) (midi_io_t *, unsigned char *, size_t);
/** Pointer to a backend-specific implementation of midi_error(). */
typedef const char * (*m_error) (midi_io_t *);
/** The size of the internal read buffer. */
#define MIDI_IO_BUFFER_SIZE 256
/** An abstracted MIDI port.
* This structure represents an opened MIDI port.
*/
struct midi_io
{
/* Backend-dependent functions. */
struct {
/** Pointer to a midi_close() implementation. */
m_close close;
m_write write;
m_read read;
m_error error;
/** Pointer to a midi_write() implementation. */
m_write write;
/** Pointer to a midi_read() implementation. */
m_read read;
/** Pointer to a midi_error() implementation. */
m_error error;
} backend;
/* Common data. */
/** The error code of the last read or write operation. */
int error;
/** The input buffer. */
unsigned char buffer[MIDI_IO_BUFFER_SIZE];
/** The current position in the input buffer. */
size_t pos;
/** The number of available bytes in the input buffer. */
size_t len;
/** The current MIDI Status Byte. */
unsigned char status;
/* Backend-dependent data. */
/** Backend-dependent data. */
union {
#ifdef HAVE_ALSA
struct {
@ -301,8 +335,22 @@ oss_midi_get_ports(char ***ports, size_t *n, size_t *max)
/* Backend-independent functions. */
/**
* Open a MIDI port.
* This function opens the MIDI port identified by the specified
* name. It allocates a midi_io structure which should be used
* for all consecutive operations on that port.
*
* When no longer needed, the port should be closed by calling
* the midi_close() function.
*
* @note The port name determines which MIDI backend will be
* used; all available backends are tried successively until
* one of them recognizes the name as a valid port name.
*
* @param[in] name The name of the MIDI port to open.
*
* @return
* - A pointer to a newly allocated @c midi_io_t object;
* - A pointer to a newly allocated midi_io object;
* - @c NULL if an error occured.
*/
midi_io_t *
@ -324,6 +372,10 @@ midi_open(const char *name)
}
/**
* Close a MIDI port.
* This function closes the MIDI port and frees the associated
* resources.
*
* @return
* - 0 if the port was successfully closed;
* - -1 if an error occured.
@ -337,6 +389,17 @@ midi_close(midi_io_t *midi)
}
/**
* Write to a MIDI port.
* This function writes arbitrary data to the MIDI port. It
* does not perform any kind of check on the data before
* sending them to the MIDI port; it is the caller's
* responsibility to provide this function with valid and
* meaningful MIDI data.
*
* @param[in] midi The MIDI port to write to.
* @param[in] buffer The MIDI data to write.
* @param[in] len The number of bytes from @a buffer to write.
*
* @return
* - The number of bytes written to the port;
* - -1 if an error occured.
@ -351,6 +414,17 @@ midi_write(midi_io_t *midi, unsigned char *buffer, size_t len)
}
/**
* Read from a MIDI port.
* This function reads data from the MIDI port and stores it
* in the provided buffer.
*
* Note that MIDI messages may be split between two calls of
* this function.
*
* @param[in] midi The MIDI port to read from.
* @param[out] buffer The buffer where to store read data.
* @param[in] len The size of the @a buffer store.
*
* @return
* - The number of bytes read and stored into @a buffer;
* - -1 if an error occured.
@ -365,8 +439,15 @@ midi_read(midi_io_t *midi, unsigned char *buffer, size_t len)
}
/**
* Get a description for the last error.
* This function gets an error message for the last error
* that occured during a write or read operation.
*
* @param[in] midi The MIDI port.
*
* @return
* A static string containing the user-readable error message.
* A static string containing the user-readable error message,
* or @c NULL if the last I/O operation was successful.
*/
const char *
midi_error(midi_io_t *midi)
@ -377,6 +458,10 @@ midi_error(midi_io_t *midi)
}
/**
* List available MIDI ports.
* This function returns a list of all available MIDI ports
* for all the supported backends.
*
* @return
* A newly allocated null-terminated array of strings, each
* string being the name of a MIDI port. Freeing each string
@ -408,6 +493,11 @@ midi_get_ports(void)
}
/**
* Read a MIDI byte.
* This function reads a single MIDI byte from the MIDI port.
*
* @param[in] midi The MIDI port to read from.
*
* @return
* - A single MIDI byte;
* - -1 if an error occured.
@ -438,6 +528,12 @@ midi_next(midi_io_t *midi)
}
/**
* Get the current Status Byte.
* This function returns the current (Running) Status Byte in
* the input MIDI stream.
*
* @param[in] midi The MIDI port.
*
* @return
* The last MIDI Status byte encountered.
*/
@ -448,6 +544,15 @@ midi_status(midi_io_t *midi)
}
/**
* Emit a Program Change message.
* This function emits Bank Select and Program Change messages
* to the specified MIDI channel.
*
* @param[in] midi The MIDI port to write to.
* @param[in] channel The MIDI channel to write to.
* @param[in] bank The bank number to select.
* @param[in] program The program number to change to.
*
* @return
* - 0 if the messages were successfully sent;
* - -1 if an error occured.
@ -479,6 +584,10 @@ midi_change_program(midi_io_t *midi,
return midi_write(midi, msg, sizeof(msg)) == sizeof(msg) ? 0 : -1;
}
/**
* General MIDI patches.
* This array contains the names of the standard GM patches.
*/
const char *midi_gm_patches[] = {
"Acoustic Grand Piano",
"Bright Acoustic Piano",


+ 50
- 1
src/sysex.c View File

@ -16,6 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file sysex.c
* System Exclusive support module.
*
* This module provides helper functions to handle System Exclusive
* (SysEx) MIDI messages.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@ -23,6 +30,17 @@
#include <sysex.h>
/**
* Read a System Exclusive message.
* This function reads a single System Exclusive message.
* Realtime messages possibly interspersed inside the System
* Exclusive message are discarded. Incomplete SysEx messages,
* interrupted from the sending side before the terminating
* byte is received, are also discarded.
*
* @param[in] midi The MIDI port to read from.
* @param[out] data The buffer where to store the message.
* @param[in] len The size of the @a data buffer.
*
* @return
* - The number of bytes read and stored in the @a data buffer.
*
@ -31,7 +49,8 @@
* byte (0xF7); if it is not, the buffer was not large enough to
* hold the entire message, and the caller may call the function
* again to get the rest of the message.
* - 0 if the SysEx message was abruptly interrupted.
* - 0 if there was no SysEx message, or if it was abruptely
* interrupted.
* - -1 if an I/O error occured.
*/
ssize_t
@ -92,6 +111,17 @@ sysex_read(midi_io_t *midi, unsigned char *data, size_t len)
}
/**
* Send a MIDI message and get a SysEx reply.
* This function writes the provided data to the MIDI port and
* read a single SysEx message in reply if any.
*
* @param[in] midi The MIDI port.
* @param[in] query The data to write.
* @param[in] query_len The number of bytes from the @a query
* buffer to write.
* @param[out] reply The buffer where to store the reply.
* @param[in] reply_len The size of the @a reply buffer.
*
* @return
* - The number of bytes read and stored in the @a reply buffer;
* - 0 if the reply message was abruptly terminated;
@ -113,6 +143,17 @@ sysex_query(midi_io_t *midi,
}
/**
* Identify a connected MIDI device.
* This function sends an universal Device Inquiry System
* Exclusive message to the MIDI port and read the reply,
* which is expected to contain informations about the
* connected MIDI device.
*
* @param[in] midi The MIDI port.
* @param[out] devid A midi_device_id structure which is
* to be filled in with the received
* informations.
*
* @return
* - 1 if the identify attempt was successful;
* - 0 if the reply was not a valid Device Inquiry Reply;
@ -168,6 +209,14 @@ struct manufacturer
};
/**
* Get the name of the MIDI manufacturer with the specified ID.
* This function lookups a internal list of MIDI manufacturers
* and return the name of the manufacturer with the specified
* identifier.
*
* @param[in] id A positive integer identifying a MIDI
* manufacturer.
*
* @return
* A static string containing the name of the MIDI manufacturer
* with the specified @a id.


+ 15
- 0
src/sysex.h View File

@ -21,11 +21,26 @@
#include <midi.h>
/**
* Informations about a MIDI device.
* This structure holds the informations that a device is expected
* to send in response to an universal Device Inquiry System
* Exclusive message.
*/
typedef struct midi_device_id
{
/** The identifier of the manufacturer of the device. */
unsigned int manufacturer;
/** A manufacturer-specific code identifying the device
* family among all the products from that manufacturer. */
unsigned int family;
/** A family-specific code identifying the device among
* all the products of that family. */
unsigned int model;
/** A version number for the device. */
unsigned int version;
} midi_device_id_t;


Loading…
Cancel
Save