This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| XM Player Submitted by

This is a small XM replay library i have been working on for some weeks. It also included players for MOD/S3M/IT, but these are too buggy to be released. It is kept portable and should work on any c compiler with not too many changes (critical sections / device driver). Maybe I'll release the complete library with MOD/S3M/XM/IT some day, but there's still quite some work to be done.. The library is released as public domain. Use it for whatever you want, I won't care.

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/vbf/vbf_util.c] - (9,199 bytes)

    #include <vbf/vbf_util.h>

    // to do:
    // - read_line_*()

    int
    vbf_read_u64(vbf_t *vbf, int endianess, u64 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, (char*)val, sizeof(u64), &size) < 0)
    	{
    		return status;
    	}

    	if (size != sizeof(u64))
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		*val = ((*val & 0xff00000000000000) >> 56) +
    			   ((*val & 0x00ff000000000000) >> 40) +
    			   ((*val & 0x0000ff0000000000) >> 24) +
    			   ((*val & 0x000000ff00000000) >>  8) +
    			   ((*val & 0x00000000ff000000) <<  8) +
    			   ((*val & 0x0000000000ff0000) << 24) +
    			   ((*val & 0x000000000000ff00) << 40) +
    			   ((*val & 0x00000000000000ff) << 56);
    	}

    	return 0;
    }

    int
    vbf_read_i64(vbf_t *vbf, int endianess, i64 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(i64), &size) < 0)
    	{
    		return status;
    	}

    	if (size != sizeof(i64))
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		*val = ((*val & 0xff00000000000000) >> 56) +
    			   ((*val & 0x00ff000000000000) >> 40) +
    			   ((*val & 0x0000ff0000000000) >> 24) +
    			   ((*val & 0x000000ff00000000) >>  8) +
    			   ((*val & 0x00000000ff000000) <<  8) +
    			   ((*val & 0x0000000000ff0000) << 24) +
    			   ((*val & 0x000000000000ff00) << 40) +
    			   ((*val & 0x00000000000000ff) << 56);
    	}

    	return 0;
    }

    int
    vbf_read_u32(vbf_t *vbf, int endianess, u32 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(u32), &size) < 0)
    	{
    		return status;
    	}

    	if (size != sizeof(u32))
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		*val = ((*val & 0xff000000) >> 24) +
    			   ((*val & 0x00ff0000) >>  8) +
    			   ((*val & 0x0000ff00) <<  8) +
    			   ((*val & 0x000000ff) << 24);
    	}

    	return 0;
    }

    int
    vbf_read_i32(vbf_t *vbf, int endianess, i32 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(i32), &size) < 0)
    	{
    		return status;
    	}

    	if (size != sizeof(i32))
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		*val = ((*val & 0xff000000) >> 24) +
    			   ((*val & 0x00ff0000) >>  8) +
    			   ((*val & 0x0000ff00) <<  8) +
    			   ((*val & 0x000000ff) << 24);
    	}

    	return 0;
    }

    int
    vbf_read_u16(vbf_t *vbf, int endianess, u16 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(u16), &size) < 0)
    	{
    		return status;
    	}

    	if (size != sizeof(u16))
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		*val = ((*val & 0xff00) >> 8) +
    			   ((*val & 0x00ff) << 8);
    	}

    	return 0;
    }

    int
    vbf_read_i16(vbf_t *vbf, int endianess, i16 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(i16), &size) < 0)
    	{
    		return status;
    	}

    	if (size != sizeof(i16))
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		*val = ((*val & 0xff00) >> 8) +
    			   ((*val & 0x00ff) << 8);
    	}

    	return 0;
    }

    int
    vbf_read_u8(vbf_t *vbf, int endianess, u8 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(u8), &size) < 0)
    	{
    		return status;
    	}

    	if (size != sizeof(u8))
    	{
    		return VBF_ERR_GENERIC;
    	}

    	return 0;
    }

    int
    vbf_read_i8(vbf_t *vbf, int endianess, i8 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(i8), &size) < 0)
    	{
    		return status;
    	}

    	if (size != sizeof(i8))
    	{
    		return VBF_ERR_GENERIC;
    	}

    	return 0;
    }

    int
    vbf_read_float32(vbf_t *vbf, int endianess, float32 *val)
    {
    	return vbf_read_u32(vbf, endianess, (u32*)val);
    }

    int
    vbf_read_float64(vbf_t *vbf, int endianess, float64 *val)
    {
    	return vbf_read_u64(vbf, endianess, (u64*)val);
    }

    int
    vbf_read_array_u64(vbf_t *vbf, int endianess, int num, u64 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, (char*)val, sizeof(u64) * num, &size) < 0)
    	{
    		return status;
    	}

    	if ((unsigned int)size != sizeof(u64) * num)
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		while(num--)
    		{
    			*val = ((*val & 0xff00000000000000) >> 56) +
    				   ((*val & 0x00ff000000000000) >> 40) +
    				   ((*val & 0x0000ff0000000000) >> 24) +
    				   ((*val & 0x000000ff00000000) >>  8) +
    				   ((*val & 0x00000000ff000000) <<  8) +
    				   ((*val & 0x0000000000ff0000) << 24) +
    				   ((*val & 0x000000000000ff00) << 40) +
    				   ((*val & 0x00000000000000ff) << 56);
    			val++;
    		}
    	}

    	return 0;
    }

    int
    vbf_read_array_i64(vbf_t *vbf, int endianess, int num, i64 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(i64) * num, &size) < 0)
    	{
    		return status;
    	}

    	if ((unsigned int)size != sizeof(i64) * num)
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		while(num--)
    		{
    			*val = ((*val & 0xff00000000000000) >> 56) +
    				   ((*val & 0x00ff000000000000) >> 40) +
    				   ((*val & 0x0000ff0000000000) >> 24) +
    				   ((*val & 0x000000ff00000000) >>  8) +
    				   ((*val & 0x00000000ff000000) <<  8) +
    				   ((*val & 0x0000000000ff0000) << 24) +
    				   ((*val & 0x000000000000ff00) << 40) +
    				   ((*val & 0x00000000000000ff) << 56);
    			val++;
    		}
    	}

    	return 0;
    }

    int
    vbf_read_array_u32(vbf_t *vbf, int endianess, int num, u32 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(u32) * num, &size) < 0)
    	{
    		return status;
    	}

    	if ((unsigned int)size != sizeof(u32) * num)
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		while(num--)
    		{
    			*val = ((*val & 0xff000000) >> 24) +
    				   ((*val & 0x00ff0000) >>  8) +
    				   ((*val & 0x0000ff00) <<  8) +
    				   ((*val & 0x000000ff) << 24);
    			val++;
    		}
    	}

    	return 0;
    }

    int
    vbf_read_array_i32(vbf_t *vbf, int endianess, int num, i32 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(i32) * num, &size) < 0)
    	{
    		return status;
    	}

    	if ((unsigned int)size != sizeof(i32) * num)
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		while(num--)
    		{
    			*val = ((*val & 0xff000000) >> 24) +
    				   ((*val & 0x00ff0000) >>  8) +
    				   ((*val & 0x0000ff00) <<  8) +
    				   ((*val & 0x000000ff) << 24);
    			val++;
    		}
    	}

    	return 0;
    }

    int
    vbf_read_array_u16(vbf_t *vbf, int endianess, int num, u16 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(u16) * num, &size) < 0)
    	{
    		return status;
    	}

    	if ((unsigned int)size != sizeof(u16) * num)
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		while(num--)
    		{
    			*val = ((*val & 0xff00) >> 8) +
    				   ((*val & 0x00ff) << 8);
    			val++;
    		}
    	}

    	return 0;
    }

    int
    vbf_read_array_i16(vbf_t *vbf, int endianess, int num, i16 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(i16) * num, &size) < 0)
    	{
    		return status;
    	}

    	if ((unsigned int)size != sizeof(i16) * num)
    	{
    		return VBF_ERR_GENERIC;
    	}

    #ifdef SYS_SMALL_ENDIAN
    	if (endianess == VBF_BIG_ENDIAN)
    #else
    	if (endianess == VBF_SMALL_ENDIAN)
    #endif
    	{
    		while(num--)
    		{
    			*val = ((*val & 0xff00) >> 8) +
    				   ((*val & 0x00ff) << 8);
    		}
    	}

    	return 0;
    }

    int
    vbf_read_array_u8(vbf_t *vbf, int endianess, int num, u8 *val)
    {
    	vbf_size_t size;
    	int status;

    	if (status = vbf_read(vbf, val, sizeof(u8) * num, &size) < 0)
    	{
    		return status;
    	}

    	if ((unsigned int)size != sizeof(u8) * num)
    	{
    		return VBF_ERR_GENERIC;
    	}

    	return 0;
    }

    int
    vbf_read_array_i8(vbf_t *vbf, int endianess, int num, i8 *val)
    {
    	return vbf_read_array_u8(vbf, endianess, num, (u8*)val);
    }

    int
    vbf_read_array_float32(vbf_t *vbf, int endianess, int num, float32 *val)
    {
    	return vbf_read_array_u32(vbf, endianess, num, (u32*)val);
    }

    int
    vbf_read_array_float64(vbf_t *vbf, int endianess, int num, float64 *val)
    {
    	return vbf_read_array_u64(vbf, endianess, num, (u64*)val);
    }

    int
    vbf_read_line_char(vbf_t *vbf, char *buf, int max, int *read)
    {
    	return VBF_ERR_GENERIC;
    }

    int
    vbf_read_line_wide_char(vbf_t *vbf, int endianess, wide_char *buf, int max, int *read)
    {
    	return VBF_ERR_GENERIC;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/vbf/vbf.c] - (4,505 bytes)

    #include <vbf/vbf.h>

    /*

    to do
    -----

    - equivalent of ungetc(...) ??

    */

    static int vbf_raw_read(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_raw_write(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_raw_ioctl(struct vbf_s *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_raw_seek_rel(struct vbf_s *vbf, vbf_size_t new_pos);
    static int vbf_raw_close(struct vbf_s *vbf);

    int
    vbf_create(vbf_t *vbf)
    {
    	vbf->data   = 0;
    	vbf->mode   = 0;
    	vbf->length = 0;
    	vbf->pos    = 0;

    	vbf->raw_read     = vbf_raw_read;
    	vbf->raw_write    = vbf_raw_write;
    	vbf->raw_ioctl    = vbf_raw_ioctl;
    	vbf->raw_seek_rel = vbf_raw_seek_rel;
    	vbf->raw_close    = vbf_raw_close;

    	return 0;
    }

    int
    vbf_destroy(vbf_t *vbf)
    {
    	if (vbf->mode & VBF_ATTR_OPEN)
    	{
    		return vbf_close(vbf);
    	}

    	return 0;
    }

    int
    vbf_seek_beg(vbf_t *vbf, vbf_size_t pos)
    {
    	vbf_size_t new_pos;

    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	if (vbf->mode & VBF_ATTR_SEEK == 0)
    	{
    		return VBF_ERR_NO_SEEK;
    	}

    	if (vbf->mode & VBF_ATTR_LENGTH == 0)
    	{
    		return VBF_ERR_NO_LENGTH;
    	}

    	if (pos < 0 || pos > vbf->length)
    	{
    		return VBF_ERR_BAD_POS;
    	}

    	new_pos = pos - vbf->pos;

    	if (!new_pos)
    	{
    		return 0;
    	}

    	return vbf->raw_seek_rel(vbf, new_pos);
    }

    int
    vbf_seek_cur(vbf_t *vbf, vbf_size_t pos)
    {
    	vbf_size_t abs_pos;

    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	if (vbf->mode & VBF_ATTR_SEEK == 0)
    	{
    		return VBF_ERR_NO_SEEK;
    	}

    	if (!pos)
    	{
    		return 0;
    	}

    	if (vbf->mode & VBF_ATTR_LENGTH)
    	{
    		abs_pos = pos + vbf->pos;

    		if (abs_pos < 0 || abs_pos > vbf->length)
    		{
    			return VBF_ERR_BAD_POS;
    		}
    	}

    	return vbf->raw_seek_rel(vbf, pos);
    }

    int
    vbf_seek_end(vbf_t *vbf, vbf_size_t pos)
    {
    	return vbf_seek_beg(vbf, vbf->length + pos);
    }

    int
    vbf_tell(vbf_t *vbf, vbf_size_t *pos)
    {
    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	if (vbf->mode & VBF_ATTR_LENGTH == 0)
    	{
    		return VBF_ERR_NO_LENGTH;
    	}

    	*pos = vbf->pos;

    	return 0;
    }

    int
    vbf_size(vbf_t *vbf, vbf_size_t *size)
    {
    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	if (vbf->mode & VBF_ATTR_LENGTH == 0)
    	{
    		return VBF_ERR_NO_LENGTH;
    	}

    	*size = vbf->length;

    	return 0;
    }

    int
    vbf_mode(vbf_t *vbf, int *mode)
    {
    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	*mode = vbf->mode;

    	return 0;
    }

    int
    vbf_read(vbf_t *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	if (vbf->mode & VBF_ATTR_READ == 0)
    	{
    		return VBF_ERR_NO_READ;
    	}

    	if (vbf->mode & VBF_ATTR_LENGTH)
    	{
    		if (vbf->pos + size > vbf->length)
    		{
    			size = vbf->length - vbf->pos;
    		}
    	}

    	return vbf->raw_read(vbf, buffer, size, out_size);
    }

    int
    vbf_write(vbf_t *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	if (vbf->mode & VBF_ATTR_WRITE == 0)
    	{
    		return VBF_ERR_NO_WRITE;
    	}

    	if (vbf->mode & VBF_ATTR_LENGTH && !(vbf->mode & VBF_ATTR_APPEND))
    	{
    		if (vbf->pos + size > vbf->length)
    		{
    			size = vbf->length - vbf->pos;
    		}
    	}

    	return vbf->raw_write(vbf, buffer, size, out_size);
    }

    int
    vbf_ioctl(vbf_t *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	return vbf->raw_ioctl(vbf, command, buffer, size, out_size);
    }

    int
    vbf_close(vbf_t *vbf)
    {
    	if (vbf->mode & VBF_ATTR_OPEN == 0)
    	{
    		return VBF_ERR_NOT_OPEN;
    	}

    	return vbf->raw_close(vbf);
    }

    static int
    vbf_raw_read(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	return VBF_ERR_GENERIC;
    }

    static int
    vbf_raw_write(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	return VBF_ERR_GENERIC;
    }

    static int
    vbf_raw_ioctl(struct vbf_s *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	return VBF_ERR_GENERIC;
    }

    static int
    vbf_raw_seek_rel(struct vbf_s *vbf, vbf_size_t new_pos)
    {
    	return VBF_ERR_GENERIC;
    }

    static int
    vbf_raw_close(struct vbf_s *vbf)
    {
    	vbf->mode = 0;

    	return 0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/vbf/vbf_std.c] - (1,816 bytes)

    #include <vbf/vbf_std.h>

    /*

    to do
    -----

    - detection of attributes

    */

    static int vbf_std_raw_read(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_std_raw_write(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_std_raw_ioctl(struct vbf_s *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_std_raw_seek_rel(struct vbf_s *vbf, vbf_size_t new_pos);
    static int vbf_std_raw_close(struct vbf_s *vbf);

    int
    vbf_std_open(vbf_t *vbf, FILE *file)
    {
    	vbf_create(vbf);

    	vbf->mode = VBF_ATTR_LENGTH | VBF_ATTR_SEEK |
    				VBF_ATTR_OPEN   | VBF_ATTR_READ;

    	vbf->data = file;

    	fseek(file, 0, SEEK_END);
    	vbf->length = ftell(file);
    	fseek(file, 0, SEEK_SET);

    	vbf->raw_read     = vbf_std_raw_read;
    	vbf->raw_write    = vbf_std_raw_write;
    	vbf->raw_ioctl    = vbf_std_raw_ioctl;
    	vbf->raw_seek_rel = vbf_std_raw_seek_rel;
    	vbf->raw_close    = vbf_std_raw_close;

    	return 0;
    }

    static int
    vbf_std_raw_read(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	if (!size)
    	{
    		return 0;
    	}

    	fread(buffer, size, 1, (FILE*)vbf->data);
    	vbf->pos += size;

    	if (out_size)
    	{
    		*out_size = size;
    	}

    	return 0;
    }

    static int
    vbf_std_raw_write(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	return 0;
    }

    static int
    vbf_std_raw_ioctl(struct vbf_s *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	return VBF_ERR_GENERIC;
    }

    static int
    vbf_std_raw_seek_rel(struct vbf_s *vbf, vbf_size_t new_pos)
    {
    	fseek((FILE*)vbf->data, new_pos, SEEK_CUR);
    	vbf->pos += new_pos;

    	return 0;
    }

    static int
    vbf_std_raw_close(struct vbf_s *vbf)
    {
    	vbf->mode = 0;

    	return 0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/vbf/vbf_mem.c] - (1,849 bytes)

    #include <vbf/vbf_mem.h>

    /*

    to do
    -----

    - add support of all attributes

    */

    static int vbf_mem_raw_read(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_mem_raw_write(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_mem_raw_ioctl(struct vbf_s *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    static int vbf_mem_raw_seek_rel(struct vbf_s *vbf, vbf_size_t new_pos);
    static int vbf_mem_raw_close(struct vbf_s *vbf);

    static void __copy_memory__(char *src, char *dst, vbf_size_t size)
    {
    	while(size-- > 0)
    	{
    		*(dst++) = *(src++);
    	}
    }

    int
    vbf_mem_open(vbf_t *vbf, void *buffer, vbf_size_t size)
    {
    	vbf_create(vbf);

    	vbf->mode = VBF_ATTR_LENGTH | VBF_ATTR_SEEK |
    				VBF_ATTR_OPEN   | VBF_ATTR_READ;

    	vbf->length = size;
    	vbf->data = buffer;

    	vbf->raw_read     = vbf_mem_raw_read;
    	vbf->raw_write    = vbf_mem_raw_write;
    	vbf->raw_ioctl    = vbf_mem_raw_ioctl;
    	vbf->raw_seek_rel = vbf_mem_raw_seek_rel;
    	vbf->raw_close    = vbf_mem_raw_close;

    	return 0;
    }

    static int
    vbf_mem_raw_read(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	__copy_memory__((char*)vbf->data + vbf->pos, (char*)buffer, size);
    	vbf->pos += size;

    	if (out_size)
    	{
    		*out_size = size;
    	}

    	return 0;
    }

    static int
    vbf_mem_raw_write(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	return 0;
    }

    static int
    vbf_mem_raw_ioctl(struct vbf_s *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size)
    {
    	return VBF_ERR_GENERIC;
    }

    static int
    vbf_mem_raw_seek_rel(struct vbf_s *vbf, vbf_size_t new_pos)
    {
    	vbf->pos += new_pos;

    	return 0;
    }

    static int
    vbf_mem_raw_close(struct vbf_s *vbf)
    {
    	vbf->mode = 0;

    	return 0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/biquad.c] - (3,988 bytes)

    #include <mpl/biquad.h>
    #include <math.h>

    #define LN2O2 0.34657359027997265470861606072909

    void
    mpl__biquad_lp(mpl__biquad_coeff_t *biquad, float32 omega, float32 bandwidth)
    {
    	float64 sn, cs, al, a0, a1, a2, b0, b1, b2, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = (1 - cs) * 0.5;
    	b1 = 1 - cs;
    	b2 = (1 - cs) * 0.5;
    	a0 = 1 + al;
    	a1 = -2 * cs;
    	a2 = 1 - al;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    void
    mpl__biquad_bp(mpl__biquad_coeff_t *biquad, float32 omega, float32 bandwidth)
    {
    	float64 sn, cs, al, a0, a1, a2, b0, b1, b2, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = al;
    	b1 = 0;
    	b2 = -al;
    	a0 = 1 + al;
    	a1 = -2 * cs;
    	a2 = 1 - al;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    void
    mpl__biquad_hp(mpl__biquad_coeff_t *biquad, float32 omega, float32 bandwidth)
    {
    	float64 sn, cs, al, a0, a1, a2, b0, b1, b2, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = (1 + cs) * 0.5;
    	b1 = -(1 + cs);
    	b2 = (1 + cs) * 0.5;
    	a0 = 1 + al;
    	a1 = -2 * cs;
    	a2 = 1 - al;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    void
    mpl__biquad_no(mpl__biquad_coeff_t *biquad, float32 omega, float32 bandwidth)
    {
    	float64 sn, cs, al, a0, a1, a2, b0, b1, b2, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = 1;
    	b1 = -2 * cs;
    	b2 = 1;
    	a0 = 1 + al;
    	a1 = b1;
    	a2 = 1 - al;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    void
    mpl__biquad_peq(mpl__biquad_coeff_t *biquad, float32 omega, float32 bandwidth, float32 dbgain)
    {
    	float64 sn, cs, al, a, a0, a1, a2, b0, b1, b2, ooa, ooa0;

    	sn = sin(omega);
    	cs = cos(omega);
    	a  = pow(10, dbgain * 0.025);
    	ooa = 1.0 / a;
    	al = sn * sinh(LN2O2 * bandwidth * omega / sn);

    	b0 = 1 + al * a;
    	b1 = -2 * cs;
    	b2 = 1 - al * a;
    	a0 = 1 + al * ooa;
    	a1 = b1;
    	a2 = 1 - al * ooa;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    void
    mpl__biquad_ls(mpl__biquad_coeff_t *biquad, float32 omega, float32 dbgain, float32 slope)
    {
    	float64 sn, cs, be, a, a0, a1, a2, b0, b1, b2, ooa0, ap1, am1;

    	sn  = sin(omega);
    	cs  = cos(omega);
    	a   = pow(10, dbgain * 0.025);
    	ap1 = a + 1;
    	am1 = a - 1;
    	be  = sqrt((a * a + 1) / slope - am1 * am1);

    	b0 = a * (ap1 - am1 * cs + be * sn);
    	b1 = 2* a * (am1 - ap1 * cs);
    	b2 = a * (ap1 - am1 * cs - be * sn);
    	a0 = ap1 + am1 * cs + be * sn;
    	a1 = -2 * (am1 + ap1 * cs);
    	a2 = ap1 + am1 * cs - be * sn;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

    void
    mpl__biquad_hs(mpl__biquad_coeff_t *biquad, float32 omega, float32 dbgain, float32 slope)
    {
    	float64 sn, cs, be, a, a0, a1, a2, b0, b1, b2, ooa0, ap1, am1;

    	sn  = sin(omega);
    	cs  = cos(omega);
    	a   = pow(10, dbgain * 0.025);
    	ap1 = a + 1;
    	am1 = a - 1;
    	be  = sqrt((a * a + 1) / slope - am1 * am1);

    	b0 = a * (ap1 + am1 * cs + be * sn);
    	b1 = -2 * a * (am1 + ap1 * cs);
    	b2 = a * (ap1 + am1 * cs - be * sn);
    	a0 = ap1 - am1 * cs + be * sn;
    	a1 = 2 * (am1 - ap1 * cs);
    	a2 = ap1 - am1 * cs - be * sn;

    	ooa0 = 1.0f / a0;

    	biquad->a0 = b0 * ooa0;
    	biquad->a1 = b1 * ooa0;
    	biquad->a2 = b2 * ooa0;
    	biquad->b1 = -a1 * ooa0;
    	biquad->b2 = -a2 * ooa0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/snddev.c] - (7,285 bytes)

    #include <mpl/snddev.h>

    // dev

    int
    mpl__snd_dev_set_vol(mpl__snd_dev_t *dev, float32 vol, float32 pan_lr, float32 pan_fb)
    {
    	return dev->set_vol(dev->internal_data, vol, pan_lr, pan_fb);
    }

    int
    mpl__snd_dev_get_vol(mpl__snd_dev_t *dev, float32 *vol, float32 *pan_lr, float32 *pan_fb)
    {
    	return dev->get_vol(dev->internal_data, vol, pan_lr, pan_fb);
    }

    int
    mpl__snd_dev_set_output_options(mpl__snd_dev_t *dev, mpl__snd_dev_output_t opt)
    {
    	return dev->set_output_options(dev->internal_data, opt);
    }

    int
    mpl__snd_dev_get_output_options(mpl__snd_dev_t *dev, mpl__snd_dev_output_t *opt)
    {
    	return dev->get_output_options(dev->internal_data, opt);
    }

    int
    mpl__snd_dev_set_latency(mpl__snd_dev_t *dev, int latency)
    {
    	return dev->set_latency(dev->internal_data, latency);
    }

    int
    mpl__snd_dev_get_latency(mpl__snd_dev_t *dev)
    {
    	return dev->get_latency(dev->internal_data);
    }

    int
    mpl__snd_dev_set_option(mpl__snd_dev_t *dev, char *option, char *value)
    {
    	return dev->set_option(dev->internal_data, option, value);
    }

    int
    mpl__snd_dev_get_option(mpl__snd_dev_t *dev, char *option, char **value)
    {
    	return dev->get_option(dev->internal_data, option, value);
    }

    int
    mpl__snd_dev_get_proc(mpl__snd_dev_t *dev, char *name, void_func_t *proc)
    {
    	return dev->get_proc(dev->internal_data, name, proc);
    }

    int
    mpl__snd_dev_create_mixer(mpl__snd_dev_t *dev, mpl__snd_mixer_t **mixer, mpl__snd_mixer_opt_t opt)
    {
    	return dev->create_mixer(dev->internal_data, mixer, opt);
    }

    int
    mpl__snd_dev_destroy_mixer(mpl__snd_dev_t *dev, mpl__snd_mixer_t *mixer)
    {
    	return dev->destroy_mixer(dev->internal_data, mixer);
    }

    int
    mpl__snd_dev_create_stream(mpl__snd_dev_t *dev, mpl__snd_stream_t **stream, mpl__snd_stream_opt_t opt)
    {
    	return dev->create_stream(dev->internal_data, stream, opt);
    }

    int
    mpl__snd_dev_destroy_stream(mpl__snd_dev_t *dev, mpl__snd_stream_t *stream)
    {
    	return dev->destroy_stream(dev->internal_data, stream);
    }

    // mixer

    int
    mpl__snd_mixer_reset(mpl__snd_mixer_t *mixer)
    {
    	return mixer->reset(mixer->internal_data);
    }

    int
    mpl__snd_mixer_pause(mpl__snd_mixer_t *mixer)
    {
    	return mixer->pause(mixer->internal_data);
    }

    int
    mpl__snd_mixer_stop(mpl__snd_mixer_t *mixer)
    {
    	return mixer->stop(mixer->internal_data);
    }

    int
    mpl__snd_mixer_upload_sample(mpl__snd_mixer_t *mixer, mpl__snd_mixer_smp_t sample)
    {
    	return mixer->upload_sample(mixer->internal_data, sample);
    }

    int
    mpl__snd_mixer_destroy_sample(mpl__snd_mixer_t *mixer, int handle)
    {
    	return mixer->destroy_sample(mixer->internal_data, handle);
    }

    int
    mpl__snd_mixer_set_vol(mpl__snd_mixer_t *mixer, float32 vol, float32 pan_lr, float32 pan_fb)
    {
     	return mixer->set_vol(mixer->internal_data, vol, pan_lr, pan_fb);
    }

    int
    mpl__snd_mixer_get_vol(mpl__snd_mixer_t *mixer, float32 *vol, float32 *pan_lr, float32 *pan_fb)
    {
    	return mixer->get_vol(mixer->internal_data, vol, pan_lr, pan_fb);
    }

    int
    mpl__snd_mixer_get_output_options(mpl__snd_mixer_t *mixer, mpl__snd_dev_output_t *opt)
    {
    	return mixer->get_output_options(mixer->internal_data, opt);
    }

    int
    mpl__snd_mixer_get_latency(mpl__snd_mixer_t *mixer)
    {
    	return mixer->get_latency(mixer->internal_data);
    }

    int
    mpl__snd_mixer_get_num_channels(mpl__snd_mixer_t *mixer)
    {
    	return mixer->get_num_channels(mixer->internal_data);
    }

    int
    mpl__snd_mixer_get_num_active_channels(mpl__snd_mixer_t *mixer)
    {
    	return mixer->get_num_active_channels(mixer->internal_data);
    }

    int
    mpl__snd_mixer_get_free_channel(mpl__snd_mixer_t *mixer)
    {
    	return mixer->get_free_channel(mixer->internal_data);
    }

    int
    mpl__snd_mixer_is_channel_active(mpl__snd_mixer_t *mixer, int ch)
    {
    	return mixer->is_channel_active(mixer->internal_data, ch);
    }

    int
    mpl__snd_mixer_set_channel_vol(mpl__snd_mixer_t *mixer, int ch, float32 vol, float32 pan_lr, float32 pan_fb)
    {
    	return mixer->set_channel_vol(mixer->internal_data, ch, vol, pan_lr, pan_fb);
    }

    int
    mpl__snd_mixer_set_channel_freq(mpl__snd_mixer_t *mixer, int ch, float freq)
    {
    	return mixer->set_channel_freq(mixer->internal_data, ch, freq);
    }

    int
    mpl__snd_mixer_set_channel_pos(mpl__snd_mixer_t *mixer, int ch, double pos, int dir)
    {
    	return mixer->set_channel_pos(mixer->internal_data, ch, pos, dir);
    }

    int
    mpl__snd_mixer_play_channel(mpl__snd_mixer_t *mixer, int ch, int handle, float32 freq, float32 vol, float32 pan_lr, float32 pan_fb, float64 pos, int dir)
    {
    	return mixer->play_channel(mixer->internal_data, ch, handle, freq, vol, pan_lr, pan_fb, pos, dir);
    }

    int
    mpl__snd_mixer_stop_channel(mpl__snd_mixer_t *mixer, int ch)
    {
    	return mixer->stop_channel(mixer->internal_data, ch);
    }

    int
    mpl__snd_mixer_set_option(mpl__snd_mixer_t *mixer, char *option, char *value)
    {
    	return mixer->set_option(mixer->internal_data, option, value);
    }

    int
    mpl__snd_mixer_get_option(mpl__snd_mixer_t *mixer, char *option, char **value)
    {
    	return mixer->get_option(mixer->internal_data, option, value);
    }

    int
    mpl__snd_mixer_get_proc(mpl__snd_mixer_t *mixer, char *name, void_func_t *proc)
    {
    	return mixer->get_proc(mixer->internal_data, name, proc);
    }

    int
    mpl__snd_mixer_set_call_back(mpl__snd_mixer_t *mixer, mpl__snd_call_back_t call_back)
    {
    	return mixer->set_call_back(mixer->internal_data, call_back);
    }

    // stream

    int
    mpl__snd_stream_set_vol(mpl__snd_stream_t *stream, float32 vol, float32 pan_lr, float32 pan_fb)
    {
    	return stream->set_vol(stream->internal_data, vol, pan_lr, pan_fb);
    }

    int
    mpl__snd_stream_get_vol(mpl__snd_stream_t *stream, float32 *vol, float32 *pan_lr, float32 *pan_fb)
    {
    	return stream->get_vol(stream->internal_data, vol, pan_lr, pan_fb);
    }

    int
    mpl__snd_stream_get_output_options(mpl__snd_stream_t *stream, mpl__snd_dev_output_t *opt)
    {
    	return stream->get_output_options(stream->internal_data, opt);
    }

    int
    mpl__snd_stream_set_input_format(mpl__snd_stream_t *stream, mpl__snd_stream_format_t *opt)
    {
    	return stream->set_input_format(stream->internal_data, opt);
    }

    int
    mpl__snd_stream_get_input_format(mpl__snd_stream_t *stream, mpl__snd_stream_format_t *opt)
    {
    	return stream->get_input_format(stream->internal_data, opt);
    }

    int
    mpl__snd_stream_get_latency(mpl__snd_stream_t *stream)
    {
    	return stream->get_latency(stream->internal_data);
    }

    int
    mpl__snd_stream_get_buffer_size(mpl__snd_stream_t *stream)
    {
    	return stream->get_buffer_size(stream->internal_data);
    }

    int
    mpl__snd_stream_set_option(mpl__snd_stream_t *stream, char *option, char *value)
    {
    	return stream->set_option(stream->internal_data, option, value);
    }

    int
    mpl__snd_stream_get_option(mpl__snd_stream_t *stream, char *option, char **value)
    {
    	return stream->get_option(stream->internal_data, option, value);
    }

    int
    mpl__snd_stream_get_proc(mpl__snd_stream_t *stream, char *name, void_func_t *proc)
    {
    	return stream->get_proc(stream->internal_data, name, proc);
    }

    int
    mpl__snd_stream_write(mpl__snd_stream_t *stream, void *data, int length)
    {
    	return stream->write(stream->internal_data, data, length);
    }

    int
    mpl__snd_stream_set_call_back(mpl__snd_stream_t *stream, mpl__snd_call_back_t call_back)
    {
    	return stream->set_call_back(stream->internal_data, call_back);
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/ml.c] - (910 bytes)

    #include <mpl/ml.h>

    int
    mpl__ml_load(mpl__ml_t *ml, vbf_t *file, mpl__md_t **md)
    {
    	return ml->load(ml->internal_data, file, md);
    }

    int
    mpl__ml_destroy(mpl__ml_t *ml, mpl__md_t *md)
    {
    	return ml->destroy(ml->internal_data, md);
    }

    int
    mpl__ml_create_mp(mpl__ml_t *ml, mpl__md_t *md, mpl__msg_box_t *mb, mpl__mp_t **mp)
    {
    	return ml->create_mp(ml->internal_data, md, mb, mp);
    }

    int
    mpl__ml_destroy_mp(mpl__ml_t *ml, mpl__mp_t **mp)
    {
    	return ml->destroy_mp(ml->internal_data, mp);
    }

    int
    mpl__ml_set_option(mpl__ml_t *ml, char *option, char *value)
    {
    	return ml->set_option(ml->internal_data, option, value);
    }

    int
    mpl__ml_get_option(mpl__ml_t *ml, char *option, char **value)
    {
    	return ml->get_option(ml->internal_data, option, value);
    }

    int
    mpl__ml_get_proc(mpl__ml_t *ml, char *name, void_func_t *proc)
    {
    	return ml->get_proc(ml->internal_data, name, proc);
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/mp.c] - (1,274 bytes)

    #include <mpl/mp.h>

    int
    mpl__mp_set_dev(mpl__mp_t *mp, mpl__snd_dev_t *dev)
    {
    	return mp->set_dev(mp->internal_data, dev);
    }

    int
    mpl__mp_reset(mpl__mp_t *mp)
    {
    	return mp->reset(mp->internal_data);
    }

    int
    mpl__mp_play(mpl__mp_t *mp)
    {
    	return mp->play(mp->internal_data);
    }

    int
    mpl__mp_stop(mpl__mp_t *mp)
    {
    	return mp->stop(mp->internal_data);
    }

    int
    mpl__mp_set_loop(mpl__mp_t *mp, int loop)
    {
    	return mp->set_loop(mp->internal_data, loop);
    }

    int
    mpl__mp_set_pos(mpl__mp_t *mp, int pos)
    {
    	return mp->set_pos(mp->internal_data, pos);
    }

    int
    mpl__mp_get_pos(mpl__mp_t *mp)
    {
    	return mp->get_pos(mp->internal_data);
    }

    int
    mpl__mp_set_vol(mpl__mp_t *mp, float32 vol)
    {
    	return mp->set_vol(mp->internal_data, vol);
    }

    int
    mpl__mp_get_vol(mpl__mp_t *mp, float32 *vol)
    {
    	return mp->get_vol(mp->internal_data, vol);
    }

    int
    mpl__mp_set_option(mpl__mp_t *mp, char *option, char *value)
    {
    	return mp->set_option(mp->internal_data, option, value);
    }

    int
    mpl__mp_get_option(mpl__mp_t *mp, char *option, char **value)
    {
    	return mp->get_option(mp->internal_data, option, value);
    }

    int
    mpl__mp_get_proc(mpl__mp_t *mp, char *name, void_func_t *proc)
    {
    	return mp->get_proc(mp->internal_data, name, proc);
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/mx.c] - (1,129 bytes)

    #include <mpl/mx.h>

    int
    mpl__mixer_set_output_options(mpl__mixer_t *mx, mpl__snd_dev_output_t *opt, int latency)
    {
    	return mx->set_output_options(mx->internal_data, opt, latency);
    }

    int
    mpl__mixer_set_options(mpl__mixer_t *mx, mpl__mixer_opt_t *opt)
    {
    	return mx->set_options(mx->internal_data, opt);
    }

    int
    mpl__mixer_get_options(mpl__mixer_t *mx, mpl__mixer_opt_t *opt)
    {
    	return mx->get_options(mx->internal_data, opt);
    }

    int
    mpl__mixer_get_proc(mpl__mixer_t *mx, char *name, void_func_t *func)
    {
    	return mx->get_proc(mx->internal_data, name, func);
    }

    int
    mpl__mixer_get_interface(mpl__mixer_t *mx, mpl__snd_mixer_t **mixer)
    {
    	return mx->get_interface(mx->internal_data, mixer);
    }

    int
    mpl__mixer_set_vol(mpl__mixer_t *mx, float32 vol, float32 pan_lr, float32 pan_fb)
    {
    	return mx->set_vol(mx->internal_data, vol, pan_lr, pan_fb);
    }

    int
    mpl__mixer_mix(mpl__mixer_t *mx, void *buffer, int length)
    {
    	return mx->mix(mx->internal_data, buffer, length);
    }

    int
    mpl__mixer_get_num_active_channels(mpl__mixer_t *mx)
    {
    	return mx->get_num_active_channels(mx->internal_data);
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/dsp_std.c] - (3,679 bytes)

    #include <mpl/dsp_std.h>
    #include <mpl/sys/mem.h>

    /*
    	to do
    	-----

        - optimize (especially 24 bit adding)
    	- dsp_convert_format() -> 24_bit
        - dsp_resample()
    */

    int
    mpl__dsp_add(void *src, void *dst, int size, int ch_num, float32 vol, int format)
    {
    	int num;

    	num = size * ch_num;

    	switch(format)
    	{
    	case MPL__SND_DEV_FMT_8BIT:
    		while(num--)
    		{
    			((i8*)dst)[num] += (i8) (((i8*)src)[num] * vol);
    		}
    		break;
    	case MPL__SND_DEV_FMT_16BIT:
    		while(num--)
    		{
    			((i16*)dst)[num] += (i16) (((i16*)src)[num] * vol);
    		}
    		break;
    	case MPL__SND_DEV_FMT_24BIT:
    		while(num--)
    		{
    //			*((i32*)dst) = ((*((i32*)dst) & 0xffffff) + (i32)((*((i32*)src) & 0xffffff) * vol)) & 0xffffff;

    //			((i8*)src) += 3;
    //			((i8*)dst) += 3;
    		}
    		break;
    	case MPL__SND_DEV_FMT_32BIT:
    		while(num--)
    		{
    			((i32*)dst)[num] += (i32) (((i32*)src)[num] * vol);
    		}
    		break;
    	case MPL__SND_DEV_FMT_FLOAT_32BIT:
    		while(num--)
    		{
    			((float32*)dst)[num] += ((float32*)src)[num] * vol;
    		}
    		break;
    	default:
    		return -1;
    	}

    	return 0;
    }

    int
    mpl__dsp_sub(void *src, void *dst, int size, int ch_num, float32 vol, int format)
    {
    	return mpl__dsp_add(src, dst, size, ch_num, -vol, format);
    }

    int
    mpl__dsp_move(void *src, void *dst, int size, int ch_num, float32 vol, int format)
    {
    	switch(format)
    	{
    	case MPL__SND_DEV_FMT_8BIT:
    		break;
    	case MPL__SND_DEV_FMT_16BIT:
    		size *= 2;
    		break;
    	case MPL__SND_DEV_FMT_24BIT:
    		size *= 3;
    		break;
    	case MPL__SND_DEV_FMT_32BIT:
    		size *= 4;
    		break;
    	case MPL__SND_DEV_FMT_FLOAT_32BIT:
    		size *= 4;
    		break;
    	default:
    		return -1;
    	}

    	size *= ch_num;

    	mpl__mem_copy(src, dst, size);

    	return 0;
    }

    int
    mpl__dsp_conv_format(void *src, void *dst, int src_format, int dst_format, int size, int ch_num, float32 vol)
    {
    	float32 *buf;
        int cnt;

        if (dst_format != MPL__SND_DEV_FMT_FLOAT_32BIT)
        {
            if (mpl__mem_alloc(4 * size * ch_num, (void**)&buf) < MPL__ERR_OK)
            {
                 return MPL__ERR_NOMEM;
            }
        }
        else
        {
            buf = (float32*) dst;
        }

        cnt = size * ch_num;

    	switch(src_format)
    	{
    	case MPL__SND_DEV_FMT_8BIT:
            vol *= 1.0f / 256.0f;
    		while(cnt--)
    		{
    			buf[cnt] = ((i8*)src)[cnt] * vol;
    		}
    		break;
    	case MPL__SND_DEV_FMT_16BIT:
            vol *= 1.0f / 65536.0f;
    		while(cnt--)
    		{
    			buf[cnt] = ((i16*)src)[cnt] * vol;
    		}
    		break;
    	case MPL__SND_DEV_FMT_24BIT:
    /*        vol *= 1.0f / 16777216.0f;
    		while(cnt--)
    		{
    			buf[cnt] = (((i32*)src)[cnt] & 0xffffff) * vol;

    			((i8*)src) += 3;
    		}*/
    		break;
    	case MPL__SND_DEV_FMT_32BIT:
            vol *= 1.0f / 4294967296.0f;
    		while(cnt--)
    		{
    			buf[cnt] = ((i32*)src)[cnt] * vol;
    		}
    		break;
    	case MPL__SND_DEV_FMT_FLOAT_32BIT:
    		while(cnt--)
    		{
    			buf[cnt] = ((float32*)src)[cnt] * vol;
    		}
    		break;
    	}

        if (dst_format == MPL__SND_DEV_FMT_FLOAT_32BIT)
        {
            return MPL__ERR_OK;
        }

        cnt = size * ch_num;

    	switch(dst_format)
    	{
    	case MPL__SND_DEV_FMT_8BIT:
            vol = 256.0f;
    		while(cnt--)
    		{
    			((i8*)dst)[cnt] = (i8)(buf[cnt] * vol);
    		}
    		break;
    	case MPL__SND_DEV_FMT_16BIT:
            vol = 65536.0f;
    		while(cnt--)
    		{
    			((i16*)dst)[cnt] = (i16)(buf[cnt] * vol);
    		}
    		break;
    	case MPL__SND_DEV_FMT_24BIT:
            vol = 16777216.0f;
    		while(cnt--)
    		{
                // how to implement it portable?!?
    		}
    		break;
    	case MPL__SND_DEV_FMT_32BIT:
            vol = 4294967296.0f;
    		while(cnt--)
    		{
    			((i32*)dst)[cnt] = (i32)(buf[cnt] * vol);
    		}
    		break;
    	}

    	mpl__mem_free(buf);

    	return MPL__ERR_OK;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/string.c] - (486 bytes)

    #include <mpl/string.h>

    int
    mpl__string_cmp_char(char *str1, char *str2)
    {
    	while(*str2 != '\0' && *str1 == *str2)
    	{
    		str1++;
    		str2++;
    	}

    	if (*str1 == *str2)
    	{
    		return MPL__STRING_EQUAL;
    	}

    	return MPL__STRING_UNEQUAL;
    }

    int
    mpl__string_cmp_wide_char(wide_char *str1, wide_char *str2)
    {
    	while(*str2 != '\0' && *str1 == *str2)
    	{
    		str1++;
    		str2++;
    	}

    	if (*str1 == *str2)
    	{
    		return MPL__STRING_EQUAL;
    	}

    	return MPL__STRING_UNEQUAL;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/sd_std.c] - (3,381 bytes)

    #include <mpl/sd_std.h>
    #include <mpl/sys/mem.h>

    static int cmd_set_vol(void *data, float32 vol, float32 pan_lr, float32 pan_fb);
    static int cmd_get_vol(void *data, float32 *vol, float32 *pan_lr, float32 *pan_fb);
    static int cmd_set_output_options(void *data, mpl__snd_dev_output_t opt);
    static int cmd_get_output_options(void *data, mpl__snd_dev_output_t *opt);
    static int cmd_set_latency(void *data, int latency);
    static int cmd_get_latency(void *data);
    static int cmd_set_option(void *data, char *option, char *value);
    static int cmd_get_option(void *data, char *option, char **value);
    static int cmd_get_proc(void *data, char *name, void_func_t *proc);
    static int cmd_create_mixer(void *data, mpl__snd_mixer_t **mixer, mpl__snd_mixer_opt_t opt);
    static int cmd_destroy_mixer(void *data, mpl__snd_mixer_t *mixer);
    static int cmd_create_stream(void *data, mpl__snd_stream_t **stream, mpl__snd_stream_opt_t opt);
    static int cmd_destroy_stream(void *data, mpl__snd_stream_t *stream);

    static int
    cmd_set_vol(void *data, float32 vol, float32 pan_lr, float32 pan_fb)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_get_vol(void *data, float32 *vol, float32 *pan_lr, float32 *pan_fb)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_set_output_options(void *data, mpl__snd_dev_output_t opt)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_get_output_options(void *data, mpl__snd_dev_output_t *opt)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_set_latency(void *data, int latency)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_get_latency(void *data)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_set_option(void *data, char *option, char *value)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_get_option(void *data, char *option, char **value)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_get_proc(void *data, char *name, void_func_t *proc)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_create_mixer(void *data, mpl__snd_mixer_t **mixer, mpl__snd_mixer_opt_t opt)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_destroy_mixer(void *data, mpl__snd_mixer_t *mixer)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_create_stream(void *data, mpl__snd_stream_t **stream, mpl__snd_stream_opt_t opt)
    {
    	return MPL__ERR_GENERIC;
    }

    static int
    cmd_destroy_stream(void *data, mpl__snd_stream_t *stream)
    {
    	return MPL__ERR_GENERIC;
    }

    int
    mpl__sd_std_create(mpl__snd_dev_t **sd, int  (*mx_create)(mpl__mixer_t **mixer), void (*mx_destroy)(mpl__mixer_t *mixer))
    {
    	int result;

    	result = mpl__mem_alloc(sizeof(mpl__snd_dev_t), (void**)sd);

    	if (result < MPL__ERR_OK)
    	{
    		return result;
    	}

    	(*sd)->create_mixer       = cmd_create_mixer;
    	(*sd)->create_stream      = cmd_create_stream;
    	(*sd)->destroy_mixer      = cmd_destroy_mixer;
    	(*sd)->destroy_stream     = cmd_destroy_stream;
    	(*sd)->get_latency        = cmd_get_latency;
    	(*sd)->get_option         = cmd_get_option;
    	(*sd)->get_output_options = cmd_get_output_options;
    	(*sd)->get_proc           = cmd_get_proc;
    	(*sd)->get_vol            = cmd_get_vol;
    	(*sd)->set_latency        = cmd_set_latency;
    	(*sd)->set_option         = cmd_set_option;
    	(*sd)->set_output_options = cmd_set_output_options;
    	(*sd)->set_vol            = cmd_set_vol;

    	return MPL__ERR_GENERIC;
    }

    void
    mpl__sd_std_destroy(mpl__snd_dev_t *sd)
    {
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/ml_xm.c] - (9,603 bytes)

    #include <mpl/sys/mem.h>
    #include <mpl/ml_xm.h>

    static int
    clip_to(int value, int min, int max)
    {
    	if (value < min)
    	{
    		return min;
    	}

    	if (value > max)
    	{
    		return max;
    	}

    	return value;
    }

    int
    mpl__xm_destruct(mpl__xm_t *xm)
    {
    	int cnt1, cnt2;

    	if (xm)
    	{
    		if (xm->inst)
    		{
    			for(cnt1 = 0; cnt1 < xm->inst_num; cnt1++)
    			{
    				if (xm->inst[cnt1].smp_num)
    				{
    					for(cnt2 = 0; cnt2 < xm->inst[cnt1].smp_num; cnt2++)
    					{
    						if (xm->inst[cnt1].smp[cnt2].data)
    						{
    							mpl__mem_free(xm->inst[cnt1].smp[cnt2].data);
    						}
    					}

    					mpl__mem_free(xm->inst[cnt1].smp);
    				}
    			}

    			mpl__mem_free(xm->inst);
    		}

    		if (xm->pat_num)
    		{
    			for(cnt1 = 0; cnt1 < xm->pat_num; cnt1++)
    			{
    				if (xm->pat[cnt1])
    				{
    					mpl__mem_free(xm->pat[cnt1]);
    				}
    			}
    		}
    	}

    	return 0;
    }

    #define return_false(err) { mpl__xm_destruct(xm); return err; }
    #define seek_to(a)	{if (vbf_seek_beg(file, a) < 0) return_false(MPL__ERR_GENERIC);}
    #define read_i8() {if (vbf_read_i8(file, VBF_SMALL_ENDIAN, &tmp_i8) < 0) return_false(MPL__ERR_GENERIC);}
    #define read_u8() {if (vbf_read_u8(file, VBF_SMALL_ENDIAN, &tmp_u8) < 0) return_false(MPL__ERR_GENERIC);}
    #define read_u16() {if (vbf_read_u16(file, VBF_SMALL_ENDIAN, &tmp_u16) < 0) return_false(MPL__ERR_GENERIC);}
    #define read_u32() {if (vbf_read_u32(file, VBF_SMALL_ENDIAN, &tmp_u32) < 0) return_false(MPL__ERR_GENERIC);}

    int
    mpl__xm_load(vbf_t *file, mpl__xm_t *xm)
    {
    	int mode, attr;
    	u8 ID[] = "Extended Module: ", raw[32], tmp_u8;
    	i8 tmp_i8;
    	u16 tmp_u16;
    	u32 tmp_u32;
    	vbf_size_t tmp_size, pos;
    	u32 h_size, packed_pat_size, ctrl, smp_index;
    	i32 cnt1, cnt2, cnt3;
    	mpl__xm_sample_t *smp;
    	mpl__xm_inst_t *inst;

    	if (vbf_mode(file, &mode) < 0)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	attr = VBF_ATTR_OPEN | VBF_ATTR_READ | VBF_ATTR_LENGTH | VBF_ATTR_SEEK;

    	if ((mode & attr) != attr)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	mpl__mem_set_zero(xm, sizeof(mpl__xm_t));

    	seek_to(0);

    	if (vbf_read(file, raw, 17, &tmp_size) < 0 || tmp_size < 17)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	for(cnt1 = 0; cnt1 < 17; cnt1++)
    	{
    		if (raw[cnt1] != ID[cnt1])
    		{
    			return MPL__ERR_GENERIC;
    		}
    	}

    	seek_to(37);

    	read_u8();

    	if (tmp_u8 != 0x1A)
    	{
    		return_false(MPL__ERR_GENERIC);
    	}

    //	to do
    //	if (vbf_read_u16(vbf, VBF_SMALL_ENDIAN, tmp_u16) < 0 || tmp_u16 != 0x104)
    //	{
    //		return_false;
    //	}

    	seek_to(17);

    	if (vbf_read(file, xm->title, 20, &tmp_size) < 0 || tmp_size < 20)
    	{
    		return_false(MPL__ERR_GENERIC);
    	}

    	xm->title[20] = 0;

    	if (vbf_seek_beg(file, 38) < 0)
    	{
    		return_false(MPL__ERR_GENERIC);
    	}

    	if (vbf_read(file, xm->tracker, 20, &tmp_size) < 0 || tmp_size < 20)
    	{
    		return_false(MPL__ERR_GENERIC);
    	}

    	xm->tracker[20] = 0;

    	seek_to(60);
    	read_u32();
    	h_size = tmp_u32;

    	read_u16();
    	xm->length      = tmp_u16;
    	read_u16();
    	xm->restart_pos = tmp_u16;
    	read_u16();
    	xm->ch_num      = tmp_u16;
    	read_u16();
    	xm->pat_num     = tmp_u16;
    	read_u16();
    	xm->inst_num    = tmp_u16;
    	read_u8();
    	xm->freq_table  = tmp_u8 & 1;
    	read_u8();
    	read_u16();
    	xm->speed       = tmp_u16;
    	read_u16();
    	xm->bpm         = tmp_u16;

    	seek_to(80);

    	for(cnt1 = 0; cnt1 < 256; cnt1++)
    	{
    		read_u8();
    		xm->order[cnt1] = tmp_u8;
    	}

    	pos = 60 + h_size;
    	seek_to(pos);

    	for(cnt1 = 0; cnt1 < xm->pat_num; cnt1++)
    	{
    		read_u32();
    		h_size = tmp_u32;
    		read_u8();
    		read_u16();
    		xm->pat_length[cnt1] = tmp_u16;
    		read_u16();
    		packed_pat_size = tmp_u16;

    		if (mpl__mem_alloc(xm->pat_length[cnt1] * xm->ch_num * sizeof(mpl__xm_cell_t),
    			(void**)&xm->pat[cnt1]) <= MPL__ERR_GENERIC)
    		{
    			return_false(MPL__ERR_NOMEM);
    		}
    		pos += h_size;
    		seek_to(pos);

    		if (!packed_pat_size)
    		{
    			for(cnt2 = 0; cnt2 < xm->pat_length[cnt1] * xm->ch_num; cnt2++)
    			{
    					xm->pat[cnt1][cnt2].key    = MPL__XM_NO_NOTE;
    					xm->pat[cnt1][cnt2].inst   = 0;
    					xm->pat[cnt1][cnt2].volume = 0;
    					xm->pat[cnt1][cnt2].effect = 0;
    					xm->pat[cnt1][cnt2].param  = 0;
    			}
    		}
    		else
    		{
    			for(cnt2 = 0; cnt2 < xm->pat_length[cnt1] * xm->ch_num; cnt2++)
    			{
    				read_u8();
    				ctrl = tmp_u8;

    				if (ctrl & 0x80)
    				{
    					if (ctrl & 1) { read_u8(); } else { tmp_u8 = MPL__XM_NO_NOTE; }
    					xm->pat[cnt1][cnt2].key    = tmp_u8 && tmp_u8 < MPL__XM_NO_NOTE ? tmp_u8 : MPL__XM_NO_NOTE;
    					if (ctrl & 2) { read_u8(); } else { tmp_u8 = 0; }
    					xm->pat[cnt1][cnt2].inst   = tmp_u8;
    					if (ctrl & 4) { read_u8(); } else { tmp_u8 = 0; }
    					xm->pat[cnt1][cnt2].volume = tmp_u8;
    					if (ctrl & 8) { read_u8(); } else { tmp_u8 = 0; }
    					xm->pat[cnt1][cnt2].effect = tmp_u8;
    					if (ctrl & 16) { read_u8(); } else { tmp_u8 = 0; }
    					xm->pat[cnt1][cnt2].param  = tmp_u8;
    				}
    				else
    				{
    					xm->pat[cnt1][cnt2].key    = ctrl && ctrl < MPL__XM_NO_NOTE ? ctrl : MPL__XM_NO_NOTE;
    					read_u8();
    					xm->pat[cnt1][cnt2].inst   = tmp_u8;
    					read_u8();
    					xm->pat[cnt1][cnt2].volume = tmp_u8;
    					read_u8();
    					xm->pat[cnt1][cnt2].effect = tmp_u8;
    					read_u8();
    					xm->pat[cnt1][cnt2].param  = tmp_u8;
    				}
    			}
    		}

    		pos += packed_pat_size;
    		seek_to(pos);
    	}

    	if (mpl__mem_alloc(sizeof(mpl__xm_inst_t) * xm->inst_num, (void**)&xm->inst) <= MPL__ERR_GENERIC)
    	{
    		return_false(MPL__ERR_NOMEM);
    	}

    	mpl__mem_set_zero(xm->inst, sizeof(mpl__xm_inst_t) * xm->inst_num);

    	smp_index = 0;

    	for(cnt1 = 0; cnt1 < xm->inst_num; cnt1++)
    	{
    		vbf_tell(file, &pos);

    		read_u32();
    		h_size = tmp_u32;

    		inst = xm->inst + cnt1;

    		if (vbf_read(file, inst->name, 22, &tmp_size) < 0 || tmp_size < 22) return_false(MPL__ERR_GENERIC);
    		inst->name[22] = 0;

    		read_u8();
    		read_u16();
    		inst->smp_num = tmp_u16;

    		if (inst->smp_num)
    		{
    			read_u32();
    			for(cnt2 = 0; cnt2 < 96; cnt2++)
    			{
    				read_u8();
    				inst->note2smp[cnt2] = tmp_u8;
    			}

    			for(cnt2 = 0; cnt2 < 12; cnt2++)
    			{
    				read_u16();
    				inst->vol_env[cnt2].x = tmp_u16;
    				read_u16();
    				inst->vol_env[cnt2].y = tmp_u16;
    			}

    			for(cnt2 = 0; cnt2 < 12; cnt2++)
    			{
    				read_u16();
    				inst->pan_env[cnt2].x = tmp_u16;
    				read_u16();
    				inst->pan_env[cnt2].y = tmp_u16;
    			}

    			read_u8();
    			inst->vol_num      = tmp_u8;
    			read_u8();
    			inst->pan_num      = tmp_u8;
    			read_u8();
    			inst->vol_sus      = tmp_u8;
    			read_u8();
    			inst->vol_loop_beg = tmp_u8;
    			read_u8();
    			inst->vol_loop_end = tmp_u8;
    			read_u8();
    			inst->pan_sus      = tmp_u8;
    			read_u8();
    			inst->pan_loop_beg = tmp_u8;
    			read_u8();
    			inst->pan_loop_end = tmp_u8;
    			read_u8();
    			inst->vol_type     = tmp_u8;
    			read_u8();
    			inst->pan_type     = tmp_u8;

    			read_u8();
    			inst->vib_type     = tmp_u8;
    			read_u8();
    			inst->vib_sweep    = tmp_u8;
    			read_u8();
    			inst->vib_depth    = tmp_u8;
    			read_u8();
    			inst->vib_rate     = tmp_u8;

    			read_u16();
    			inst->vol_fade_out = 2 * tmp_u16;
    		}

    		pos += h_size;
    		seek_to(pos);

    		if (inst->smp_num)
    		{
    			if (mpl__mem_alloc(sizeof(mpl__xm_sample_t) * inst->smp_num, (void**)&inst->smp) <= MPL__ERR_GENERIC)
    			{
    				return_false(MPL__ERR_NOMEM);
    			}

    			mpl__mem_set_zero(inst->smp, sizeof(mpl__xm_sample_t) * inst->smp_num);
    		}

    		for(cnt2 = 0; cnt2 < inst->smp_num; cnt2++)
    		{
    			smp = inst->smp + cnt2;

    			read_u32();
    			smp->length = tmp_u32;
    			read_u32();
    			smp->loop_begin = tmp_u32;
    			read_u32();
    			smp->loop_end = tmp_u32;

    			if (smp->loop_begin >= smp->length)
    			{
    				smp->loop_begin = 0;
    			}

    			smp->loop_end += smp->loop_begin;

    			if (smp->loop_end > smp->length)
    			{
    				smp->loop_end = smp->length;
    			}

    			read_u8();
    			smp->vol = tmp_u8;
    			read_i8();
    			smp->finetune = tmp_i8;
    			read_u8();
    			smp->format = tmp_u8;
    			read_u8();
    			smp->pan = tmp_u8;
    			read_i8();
    			smp->rel_note = tmp_i8;

    			if (smp->loop_begin == smp->loop_end)
    			{
    				smp->format &= ~(MPL__XM_SMP_LOOP | MPL__XM_SMP_BIDI_LOOP);
    			}

    			if (smp->format & MPL__XM_SMP_16BIT)
    			{
    				smp->length     >>= 1;
    				smp->loop_begin >>= 1;
    				smp->loop_end   >>= 1;
    			}

    			read_u8();

    			if (vbf_read(file, smp->name, 22, &tmp_size) < 0 || tmp_size < 22)
    			{
    				return_false(MPL__ERR_GENERIC);
    			}

    			smp->name[22] = 0;

    			smp->index = smp_index++;

    			if (smp->index >= 300)
    			{
    				return_false(MPL__ERR_GENERIC);
    			}
    		}

    		for(cnt2 = 0; cnt2 < inst->smp_num; cnt2++)
    		{
    			smp = inst->smp + cnt2;

    			if (smp->length == 0)
    			{
    				continue;
    			}

    			if (mpl__mem_alloc(smp->length * (1 + (smp->format & MPL__XM_SMP_16BIT ? 1 : 0)), &smp->data) <= MPL__ERR_GENERIC)
    			{
    				return_false(MPL__ERR_NOMEM);
    			}

    			if (smp->format & MPL__XM_SMP_16BIT)
    			{
    				i16 *cur = (i16*)smp->data;

    				if (vbf_read_array_i16(file, VBF_SMALL_ENDIAN, smp->length, cur) < 0)
    				{
    					return_false(MPL__ERR_GENERIC);
    				}

    				for(cnt3 = 1; cnt3 < smp->length; cnt3++)
    				{
    					cur[cnt3] += cur[cnt3 - 1];
    				}
    			}
    			else
    			{
    				i8 *cur = (i8*)smp->data;

    				if (vbf_read(file, cur, smp->length, &tmp_size) < 0 || tmp_size < smp->length)
    				{
    					return_false(MPL__ERR_GENERIC);
    				}

    				for(cnt3 = 1; cnt3 < smp->length; cnt3++)
    				{
    					cur[cnt3] += cur[cnt3 - 1];
    				}
    			}
    		}
    	}

    	xm->smp_index_num = smp_index;

    	return MPL__ERR_OK;
    }

    #undef return_false
    #undef seek_to
    #undef read_i8
    #undef read_u8
    #undef read_u16
    #undef read_u32

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/mp_xm.c] - (37,378 bytes)

    /*

    bugs
    ----

    - does MPL__XM_EFF_SMP_OFFSET retrigger?
    - cpplay.xm - ahhhhhhhhhh
    - crash while playing Enter_the_Merregnon.xm (traxinspace Merregnon compo)
    - -27-.xm by floppi -> wrong frequencies
    - instrument loading ???
    - note delay (btw note delay also has to retrigger if issued with no note!)
    - retrig ??
    - key off
    - do_vol() -> case XM_VOL_EFF_VIB
    - note with invalid sample number has to stop current sample

    to do
    -----

    - multi threading !!
    - new_note()

    */

    #include <mpl/sys/mem.h>
    #include <mpl/string.h>
    #include <mpl/mp_xm.h>
    #include <math.h>

    static int sinus_table[32]=
    {
      0, 24, 49, 74, 97,120,141,161,
    180,197,212,224,235,244,250,253,
    255,253,250,244,235,224,212,197,
    180,161,141,120, 97, 74, 49, 24
    };

    static int mp_cmd_reset(void *internal_data);

    static int
    clip_to(int value, int min, int max)
    {
    	if (value < min)
    	{
    		return min;
    	}

    	if (value > max)
    	{
    		return max;
    	}

    	return value;
    }

    static int
    linear_note_to_period(int note, int fine_tune)
    {
    	return (int)(7680.0f - note * 64.0f - fine_tune * 0.5f);
    }

    static float32
    linear_period_to_freq(int per)
    {
    	return (float32)(8363.0 * pow(2.0, (4608.0 - per) * 0.00130208333333));
    }

    static int
    note_to_period(int note, int fine_tune)
    {
    	float32 period, diff;

    	period = (float32) pow(2.0f, (132.0f - note) * 0.08333333333f) * 13.375f;

    	if (fine_tune < 0 && note)
    	{
    		diff = period - (float32)pow(2.0f, (132.0f - note + 1) * 0.08333333333f) * 13.375f;
    		diff *= (float32)fabs(fine_tune);
    		diff /= -128;
    	}
    	else
    	{
    		diff = (float32)pow(2.0f, (132.0f - note - 1) * 0.08333333333f) * 13.375f - period;
    		diff *= fine_tune;
    		diff /= 128;
    	}

    	period += diff;

    	return (int)period;
    }

    static float32
    period_to_freq(int per)
    {
    	return 14317056.0f / per;
    }

    static mpl__xm_cell_t*
    get_row(mpl__mp_xm_t *pl)
    {
    	return pl->xm->pat[pl->xm->order[pl->pat_cur]] + pl->row_cur * pl->xm->ch_num;
    }

    static void run_tick(mpl__mp_xm_t *player, int param);

    static void
    update_ctrl(mpl__mp_xm_t *pl)
    {
    	float32 vol, pan, freq;
    	mpl__snd_dev_output_t opt;
    	mpl__mp_xm_chan_t *p_ch;
    	int cur;

    	mpl__snd_mixer_get_output_options(pl->mixer, &opt);

    	for(cur = 0; cur < pl->xm->ch_num; cur++)
    	{

    		p_ch = pl->ch + cur;

    		p_ch->active = mpl__snd_mixer_is_channel_active(pl->mixer, cur);

    		if (!p_ch->active & !(p_ch->ctrl & MPL__XM_CTRL_START))
    		{
    			continue;
    		}

    		if (!p_ch->p_smp)
    		{
    			continue;
    		}

    		if (p_ch->ctrl & MPL__XM_CTRL_STOP)
    		{
    			mpl__snd_mixer_stop_channel(pl->mixer, cur);

    			p_ch->active = 0;
    			p_ch->ctrl = 0;

    			continue;
    		}

    		if (p_ch->ctrl & (MPL__XM_CTRL_START | MPL__XM_CTRL_VOL))
    		{
    			p_ch->vol = clip_to(p_ch->vol, 0, 64);

    			vol = (float32)clip_to(p_ch->vol + p_ch->vol_delta, 0, 128);
    			vol = vol * p_ch->env_vol * p_ch->fade_out_vol;
    			vol = vol * (1.0f / (64.0f * 65536.0f * 64.0f));

    			p_ch->pan = clip_to(p_ch->pan, 0, 255);

    			pan = clip_to(p_ch->pan + p_ch->pan_delta + (p_ch->env_pan << 2) - 128, 16, 239) * (1.0f / 255.0f);
    		}

    		if (p_ch->ctrl & (MPL__XM_CTRL_START | MPL__XM_CTRL_PER))
    		{
    			p_ch->per = clip_to(p_ch->per, 56, 100000);

    			if (pl->xm->freq_table & MPL__XM_FREQ_TABLE_LINEAR)
    			{
    				freq = linear_period_to_freq(clip_to(p_ch->per + p_ch->per_delta, 56, 100000));
    			}
    			else
    			{
    				freq = period_to_freq(clip_to(p_ch->per + p_ch->per_delta, 56, 100000));
    			}

    			if (freq < 50)
    			{
    				freq = 50;
    			}
    		}

    		if (p_ch->ctrl & MPL__XM_CTRL_START)
    		{
    			if (pl->smp_handle[p_ch->p_smp->index] < 0)
    			{
    				continue;
    			}

    			mpl__snd_mixer_play_channel(pl->mixer, cur, pl->smp_handle[p_ch->p_smp->index], freq, vol, pan, 0.5f, p_ch->smp_offset, MPL__SND_DEV_DIR_FORWARDS);

    			p_ch->smp_offset = 0;
    			p_ch->ctrl = 0;
    		}

    		if (p_ch->ctrl & MPL__XM_CTRL_PER)
    		{
    			mpl__snd_mixer_set_channel_freq(pl->mixer, cur, freq);
    		}

    		if (p_ch->ctrl & MPL__XM_CTRL_VOL)
    		{
    			mpl__snd_mixer_set_channel_vol(pl->mixer, cur, vol, pan, 0.5f);
    		}

    		p_ch->ctrl = 0;
    	}

    	if (pl->ctrl & MPL__XM_PL_CTRL_VOL)
    	{
    		pl->glob_vol = clip_to(pl->glob_vol, 0, 64);

    		vol = pl->vol * pl->glob_vol * (1.0f / 64.0f);

    		mpl__snd_mixer_set_vol(pl->mixer, vol, 0.5f, 0.5f);
    	}

    	if (pl->ctrl & MPL__XM_PL_CTRL_BPM)
    	{
    		mpl__snd_call_back_t cb;

    		cb.func   = (mpl__snd_call_back_func_t)run_tick;
    		cb.data   = pl;
    		cb.param  = 0;
    		cb.period = 2500.0f / pl->bpm;

    		mpl__snd_mixer_set_call_back(pl->mixer, cb);
    	}

    	pl->ctrl = 0;
    }

    static long
    get_random()
    {
    	static long seed = 37842;
        unsigned long low, high;

    	low  = 16807 * (seed & 0xFFFF);
    	high = 16807 * (long)((unsigned long)seed >> 16);

    	low = low + ((high & 0x7FFF) << 16);

    	if (low > 2147483647L)
    	{
    		low = (low & 2147483647L) + 1;
    	}

    	low = low + (high >> 15);

    	if (low > 2147483647L)
    	{
    		low = (low & 2147483647L) + 1;
    	}

    	return seed = (long)low;
    }

    static void
    do_vibrato(mpl__mp_xm_chan_t *p_ch, int exp, int update_pos)
    {
    	int delta, temp;

    	temp = p_ch->vib_pos & 31;

    	switch (p_ch->wave_control & 3)
    	{
    		case 0:
    			delta = (int)(fabs(sin(p_ch->vib_pos * 0.0981747704246f) * 256.0f));
    			break;
    		case 1:
    /*			temp <<= 3;

    			if (p_ch->vib_pos < 0)
    			{
    				temp = 255 - temp;
    			}

    			delta = temp;
    			break;
    		case 2:
    		case 3:
    			delta = get_random() & 0xff;*/
    			break;
    	};

    	delta *= p_ch->vib_depth;
    	delta >>= 7;
    	delta <<= exp;

    	p_ch->ctrl |= MPL__XM_CTRL_PER;

    	if (p_ch->vib_pos >= 0)
    	{
    		p_ch->per_delta = -delta;
    	}
    	else
    	{
    		p_ch->per_delta = delta;
    	}

    	if (!update_pos)
    	{
    		return;
    	}

    	p_ch->vib_pos += p_ch->vib_speed;

    	if (p_ch->vib_pos > 31)
    	{
    		p_ch->vib_pos -= 64;
    	}
    }

    static void
    do_inst_vibrato(mpl__mp_xm_chan_t *p_ch)
    {
    	int delta;

    	if (!p_ch->p_inst)
    	{
    		return;
    	}

    	switch (p_ch->wave_control & 3)
    	{
    		case 0:
    			delta = (int)((sin(p_ch->inst_vib_pos * 0.0245437f)) * 64.0f);
    			break;
    		case 1:
    			delta = 64;
    			if (p_ch->inst_vib_pos > 127)
    			{
    				delta = -64;
    			}
    			break;
    		case 2:
    		case 3:
    			delta = (get_random() & 0x8f) - 64;
    			break;
    	};

    	delta *= p_ch->p_inst->vib_depth;

    	if (p_ch->p_inst->vib_sweep)
    	{
    		delta = delta * p_ch->inst_vib_sweep_pos / p_ch->p_inst->vib_sweep;
    	}

    	delta >>= 6;

    	p_ch->per_delta += delta;
    	p_ch->ctrl      |= MPL__XM_CTRL_PER;

    	if (++p_ch->inst_vib_sweep_pos > p_ch->p_inst->vib_sweep)
    	{
    		p_ch->inst_vib_sweep_pos = p_ch->p_inst->vib_sweep;
    	}

    	p_ch->inst_vib_pos += p_ch->p_inst->vib_rate;

    	if (p_ch->inst_vib_pos > 255)
    	{
    		p_ch->inst_vib_pos -= 256;
    	}
    }

    static void
    do_tremolo(mpl__mp_xm_chan_t *p_ch)
    {
        int delta;

        switch((p_ch->wave_control >> 4) & 3)
    	{
    	case 0:
    		delta = sinus_table[p_ch->tremolo_pos&31];
    		break;
    	case 1:
    		delta = p_ch->tremolo_pos < 32 ?
    				p_ch->tremolo_pos << 3 :
    				255 - (p_ch->tremolo_pos << 3);
    		break;
    	case 2:
    		delta = 255;
    		break;
    	case 3:
    		delta = get_random() & 0xff;
    		break;
        };

        delta *= p_ch->tremolo_depth;
    	delta >>= 6;

        if (p_ch->tremolo_pos < 32)
    	{
    		delta = -delta;
    	}

    	p_ch->vol_delta = delta;
    	p_ch->ctrl     |= MPL__XM_CTRL_VOL;

        p_ch->tremolo_pos += p_ch->tremolo_speed;

    	while(p_ch->tremolo_pos >= 64)
    	{
    		p_ch->tremolo_pos -= 64;
    	}
    }

    static void
    do_porta(mpl__mp_xm_chan_t *p_ch)
    {
    	if (p_ch->porta_period)
    	{
    		p_ch->per  += clip_to(p_ch->porta_period - p_ch->per, -p_ch->porta_speed, p_ch->porta_speed);
    		p_ch->ctrl |= MPL__XM_CTRL_PER;
    	}
    }

    static void
    do_tremor(mpl__mp_xm_chan_t *p_ch)
    {
    	if ((p_ch->tremor_spd >> 4) + (p_ch->tremor_spd & 15) == 0)
    	{
    		p_ch->tremor_pos = 0;
    		return;
    	}

    	p_ch->tremor_pos %= (p_ch->tremor_spd >> 4) + (p_ch->tremor_spd & 15);

    	if (p_ch->tremor_pos < (p_ch->tremor_spd >> 4))
    	{
    		p_ch->vol_delta = 0;
    	}
    	else
    	{
    		p_ch->vol_delta = -p_ch->vol;
    	}

    	p_ch->ctrl |= MPL__XM_CTRL_VOL;

    	p_ch->tremor_pos++;
    }

    static void
    do_env_vol(mpl__mp_xm_chan_t *p_ch)
    {
    	mpl__xm_point_t *cur, *next;
    	int pos, tick_inc = 1, divide;

    	if (!p_ch->p_inst->vol_num)
    	{
    		return;
    	}

    	pos = 0;

    	if (p_ch->p_inst->vol_num > 1)
    	{
    		while(p_ch->env_vol_tick >= p_ch->p_inst->vol_env[pos + 1].x && pos < p_ch->p_inst->vol_num - 1)
    		{
    			pos++;
    		}
    	}

    	if (p_ch->env_vol_tick == p_ch->p_inst->vol_env[pos].x)
    	{
    		if ((p_ch->p_inst->vol_type & MPL__XM_ENV_LOOP) &&
    			pos == p_ch->p_inst->vol_loop_end)
    		{
    			pos                = p_ch->p_inst->vol_loop_beg;
    			p_ch->env_vol_tick = p_ch->p_inst->vol_env[pos].x;
    		}

    		if ((p_ch->p_inst->vol_type & MPL__XM_ENV_SUSTAIN) && pos == p_ch->p_inst->vol_sus && !p_ch->key_off)
    		{
    			tick_inc = 0;
    		}

    		if (pos == p_ch->p_inst->vol_num - 1)
    		{
    			tick_inc = 0;
    		}
    	}

    	cur  = p_ch->p_inst->vol_env + pos;
    	next = cur;

    	if (p_ch->p_inst->vol_num > 1 && pos < p_ch->p_inst->vol_num - 1)
    	{
    		next++;
    	}

    	divide = next->x - cur->x;

    	if (divide > 1)
    	{
    		p_ch->env_vol = cur->y + (next->y - cur->y) * (p_ch->env_vol_tick - cur->x) / divide;
    	}
    	else
    	{
    		p_ch->env_vol = cur->y;
    	}

    	p_ch->ctrl |= MPL__XM_CTRL_VOL;

    	if (tick_inc)
    	{
    		p_ch->env_vol_tick++;
    	}
    }

    static void
    do_env_pan(mpl__mp_xm_chan_t *p_ch)
    {
    	mpl__xm_point_t *cur, *next;
    	int pos, tick_inc = 1, divide;

    	if (!p_ch->p_inst->pan_num)
    	{
    		p_ch->env_pan_tick++;
    		return;
    	}

    	pos = 0;

    	if (p_ch->p_inst->pan_num > 1)
    	{
    		while(p_ch->env_pan_tick >= p_ch->p_inst->pan_env[pos + 1].x  && pos < p_ch->p_inst->pan_num - 1)
    		{
    			pos++;
    		}
    	}

    	if (p_ch->env_pan_tick == p_ch->p_inst->pan_env[pos].x)
    	{
    		if ((p_ch->p_inst->pan_type & MPL__XM_ENV_LOOP) &&
    			pos == p_ch->p_inst->pan_loop_end)
    		{
    			pos                = p_ch->p_inst->pan_loop_beg;
    			p_ch->env_pan_tick = p_ch->p_inst->pan_env[pos].x;
    		}

    		if ((p_ch->p_inst->pan_type & MPL__XM_ENV_SUSTAIN) && pos == p_ch->p_inst->pan_sus && !p_ch->key_off)
    		{
    			tick_inc = 0;
    		}

    		if (pos == p_ch->p_inst->pan_num - 1)
    		{
    			tick_inc = 0;
    		}
    	}

    	cur  = p_ch->p_inst->pan_env + pos;
    	next = cur;

    	if (p_ch->p_inst->pan_num > 1 && pos < p_ch->p_inst->pan_num - 1)
    	{
    		next++;
    	}

    	divide = next->x - cur->x;

    	if (divide > 1)
    	{
    		p_ch->env_pan = cur->y + (next->y - cur->y) * (p_ch->env_pan_tick - cur->x) / divide;
    	}
    	else
    	{
    		p_ch->env_pan = cur->y;
    	}

    	p_ch->ctrl |= MPL__XM_CTRL_VOL;

    	if (tick_inc)
    	{
    		p_ch->env_pan_tick++;
    	}
    }

    static void
    do_vol_slide(mpl__mp_xm_chan_t *p_ch, int slide_value)
    {
    	int param_x, param_y;

    	param_x = slide_value >> 4;
    	param_y = slide_value & 0xf;

    	if (param_x)
    	{
    		p_ch->vol += param_x;
    	}
    	else
    	{
    		if (param_y)
    		{
    			p_ch->vol -= param_y;
    		}
    	}

    	p_ch->ctrl |= MPL__XM_CTRL_VOL;
    }

    static void
    do_vol(mpl__mp_xm_t *pl, mpl__mp_xm_chan_t *p_ch, int vol)
    {
    	if (vol < 0x10)
    	{
    		return;
    	}

    	if (vol <= 0x50 && !pl->tick_cur)
    	{
    		p_ch->vol   = vol - 0x10;
    		p_ch->ctrl |= MPL__XM_CTRL_VOL;
    	}

    	switch(vol & 0xf0)
    	{
    	case MPL__XM_VOL_EFF_VOL_SLIDE_DOWN:
    		if (pl->tick_cur)
    		{
    			p_ch->vol  = p_ch->vol - (vol & 0xf);
    			p_ch->ctrl |= MPL__XM_CTRL_VOL;
    		}
    		break;
    	case MPL__XM_VOL_EFF_VOL_SLIDE_UP:
    		if (pl->tick_cur)
    		{
    			p_ch->vol  = p_ch->vol + (vol & 0xf);
    			p_ch->ctrl |= MPL__XM_CTRL_VOL;
    		}
    		break;
    	case MPL__XM_VOL_EFF_FINE_VOL_SLIDE_DOWN:
    		if (!pl->tick_cur)
    		{
    			p_ch->vol  = p_ch->vol - (vol & 0xf);
    			p_ch->ctrl |= MPL__XM_CTRL_VOL;
    		}
    		break;
    	case MPL__XM_VOL_EFF_FINE_VOL_SLIDE_UP:
    		if (!pl->tick_cur)
    		{
    			p_ch->vol  = p_ch->vol + (vol & 0xf);
    			p_ch->ctrl |= MPL__XM_CTRL_VOL;
    		}
    		break;
    	case MPL__XM_VOL_EFF_VIB_SPEED:
    		if (!pl->tick_cur)
    		{
    			p_ch->vib_speed = vol & 0xf;
    		}
    		break;
    	case MPL__XM_VOL_EFF_VIB:
    		if (!pl->tick_cur)
    		{
    			p_ch->vib_depth = vol & 0xf;
    			do_vibrato(p_ch, 2, 1);
    		}
    		else
    		{
    			do_vibrato(p_ch, 2, 0);
    		}

    		break;
    	case MPL__XM_VOL_EFF_PAN:
    		if (!pl->tick_cur)
    		{
    			p_ch->pan = (vol & 0xf) << 4;
    			p_ch->ctrl |= MPL__XM_CTRL_VOL;
    		}
    		break;
    	case MPL__XM_VOL_EFF_PAN_SLIDE_LEFT:
    		p_ch->pan   = p_ch->pan - (vol & 0xf);
    		p_ch->ctrl |= MPL__XM_CTRL_VOL;
    		break;
    	case MPL__XM_VOL_EFF_PAN_SLIDE_RIGHT:
    		p_ch->pan   = p_ch->pan + (vol & 0xf);
    		p_ch->ctrl |= MPL__XM_CTRL_VOL;
    		break;
    	case MPL__XM_VOL_EFF_PORTA:
    		if (vol & 0xf)
    		{
    			p_ch->porta_speed = (vol & 0xf) << 6;
    		}
    /*
    		if (pl->tick_cur)
    		{
    			do_porta(p_ch);
    		}
    		else
    		{
    			p_ch->porta_period = p_ch->dst_per;
    		}*/
    		break;
    	}
    }

    static void
    new_smp(mpl__mp_xm_chan_t *p_ch)
    {
    	if (!p_ch->p_smp || p_ch->key == MPL__XM_NO_NOTE)
    	{
    		return;
    	}

    	p_ch->vol                = p_ch->p_smp->vol;
    	p_ch->env_vol            = 64;
    	p_ch->env_vol_tick       = 0;
    	p_ch->fade_out_vol       = 65536;
    	p_ch->pan                = p_ch->p_smp->pan;
    	p_ch->env_pan            = 32;
    	p_ch->env_pan_tick       = 0;
    	p_ch->key_off            = 0;
    	p_ch->inst_vib_sweep_pos = 0;
    	p_ch->inst_vib_pos       = 0;
    	p_ch->retrig_vol_slide   = 1;

    	if ((p_ch->wave_control & 0xf) < 4)
    	{
    		p_ch->vib_pos = 0;
    	}

    	if ((p_ch->wave_control >> 4) < 4)
    	{
    		p_ch->tremolo_pos = 0;
    	}

    	p_ch->ctrl |= MPL__XM_CTRL_VOL;
    }

    static void
    retrig(mpl__mp_xm_chan_t *p_ch)
    {
    	if (!p_ch->p_smp || p_ch->key == MPL__XM_NO_NOTE)
    	{
    		return;
    	}

    	p_ch->env_vol            = 64;
    	p_ch->env_vol_tick       = 0;
    	p_ch->fade_out_vol       = 65536;

    	p_ch->env_pan            = 32;
    	p_ch->env_pan_tick       = 0;

    	p_ch->inst_vib_sweep_pos = 0;
    	p_ch->inst_vib_pos       = 0;

    	if ((p_ch->wave_control & 0xf) < 4)
    	{
    		p_ch->vib_pos = 0;
    	}

    	if ((p_ch->wave_control >> 4) < 4)
    	{
    		p_ch->tremolo_pos = 0;
    	}

    	p_ch->ctrl |= MPL__XM_CTRL_START | MPL__XM_CTRL_VOL;
    }

    static void
    new_note(mpl__mp_xm_chan_t *p_ch)
    {
    }

    static void
    update_row(mpl__mp_xm_t *pl)
    {
    	int ch;
    	mpl__xm_cell_t *row_cur, *cell;
    	mpl__xm_t *xm;
    	mpl__mp_xm_chan_t *p_ch;
    	mpl__msg_t msg;
    	int pattern_jump, pattern_break, porta;
    	int param, param_x, param_y;
    	int old_vol, old_pan, old_per;

    	xm = pl->xm;

    	if (pl->pat_cur >= xm->length)
    	{
    		if (pl->loop == MPL__MP_LOOP_NONE)
    		{
    			mp_cmd_reset(pl);

    			if (pl->mb)
    			{
    				msg.msg = MPL__MP_MSG_END;

    				mpl__msg_box_send(pl->mb, &msg);
    			}

    			return;
    		}

    		pl->bpm = xm->bpm;
    		pl->speed = xm->speed;
    		pl->row_cur = 0;
    		pl->pat_cur = 0;
    		pl->delay = 0;

    		if (pl->loop != MPL__MP_LOOP_FOREVER)
    		{
    			pl->loop--;
    		}

    		if (pl->mb)
    		{
    			msg.msg = MPL__MP_MSG_RESTART;

    			mpl__msg_box_send(pl->mb, &msg);
    		}
    	}

    	pattern_jump = 0;
    	pattern_break = 0;

    	pl->row_next = pl->row_cur + 1;

    	row_cur = get_row(pl);

    	for(ch = 0; ch < pl->xm->ch_num; ch++)
    	{
    		cell = &row_cur[ch];
    		p_ch  = &pl->ch[ch];

    		if (ch == 4)
    		{
    			ch = ch;
    		}

    		porta = cell->effect == MPL__XM_EFF_PORTA ||
    				cell->effect == MPL__XM_EFF_PORTA_VOL_SLIDE ||
    				(cell->volume & 0xf0) == MPL__XM_VOL_EFF_PORTA;

    		if (cell->key < MPL__XM_KEY_OFF && !porta)
    		{
    			p_ch->key = cell->key - 1;
    		}

    		if (cell->inst)
    		{
    			p_ch->inst = cell->inst;
    		}

    		if (cell->key < MPL__XM_KEY_OFF && cell->inst && !porta)
    		{
    			if (cell->inst <= xm->inst_num)
    			{
    				int note2smp;

    				p_ch->p_inst = xm->inst + p_ch->inst - 1;

    				note2smp = p_ch->p_inst->note2smp[p_ch->key];

    				if (note2smp >= p_ch->p_inst->smp_num)
    				{
    					p_ch->inst = 0;
    					p_ch->p_inst = 0;
    					p_ch->p_smp = 0;
    				}
    				else
    				{
    					p_ch->p_smp  = p_ch->p_inst->smp + note2smp;
    				}
    			}
    			else
    			{
    				p_ch->inst = 0;
    				p_ch->p_inst = 0;
    				p_ch->p_smp = 0;
    			}
    		}

    		if (p_ch->eff == MPL__XM_EFF_TREMOLO && cell->effect != MPL__XM_EFF_TREMOLO)
    		{
    			p_ch->vol += p_ch->vol_delta;
    		}

    		p_ch->vol_delta = 0;
    		p_ch->per_delta = 0;

    		if (p_ch->p_inst)
    		{
    			if (cell->key < MPL__XM_KEY_OFF)
    			{
    				int period;

    				p_ch->real_key = cell->key + p_ch->p_smp->rel_note - 1;

    				if (xm->freq_table & MPL__XM_FREQ_TABLE_LINEAR)
    				{
    					period = linear_note_to_period(p_ch->real_key, pl->smp_fine_tune[p_ch->p_smp->index]);
    				}
    				else
    				{
    					period = note_to_period(p_ch->real_key, pl->smp_fine_tune[p_ch->p_smp->index]);
    				}

    				if (porta)
    				{
    					p_ch->dst_per = period;
    				}
    				else
    				{
    					p_ch->per   = period;
    					p_ch->ctrl |= MPL__XM_CTRL_START;
    				}

    			}

    			if (cell->inst)
    			{
    				new_smp(p_ch);
    			}
    		}

    		old_vol = p_ch->vol;
    		old_pan = p_ch->pan;
    		old_per = p_ch->per;

    		do_vol(pl, p_ch, cell->volume);

    		if (cell->key == MPL__XM_KEY_OFF || cell->effect == MPL__XM_EFF_KEY_OFF)
    		{
    			p_ch->key_off = 1;
    		}

    		if (cell->effect == 0 && cell->param == 0)
    		{
    			goto no_effects;
    		}

    		param   = cell->param;
    		param_x = param >> 4;
    		param_y = param & 0xf;

    		switch(cell->effect)
    		{
    		case MPL__XM_EFF_ARPEGGIO:
    			break;
    		case MPL__XM_EFF_PORTA_UP:
    			if (param)
    			{
    				p_ch->porta_up = param << 2;
    			}
    			break;
    		case MPL__XM_EFF_PORTA_DOWN:
    			if (param)
    			{
    				p_ch->porta_down = param << 2;
    			}
    			break;
    		case MPL__XM_EFF_PORTA:
    			if (param)
    			{
    				p_ch->porta_speed = param << 2;
    			}
    			p_ch->porta_period = p_ch->dst_per;
    			break;
    		case MPL__XM_EFF_VIB:
    			if (param_x)
    			{
    				p_ch->vib_speed = param_x;
    			}
    			if (param_y)
    			{
    				p_ch->vib_depth = param_y;
    			}
    			do_vibrato(p_ch, 2, 0);
    			break;
    		case MPL__XM_EFF_PORTA_VOL_SLIDE:
    			if (param)
    			{
    				p_ch->porta_vol_slide = param;
    			}
    			p_ch->porta_period = p_ch->dst_per;
    			break;
    		case MPL__XM_EFF_VIB_VOL_SLIDE:
    			if (param)
    			{
    				p_ch->vib_vol_slide = param;
    			}
    			do_vibrato(p_ch, 2, 0);
    			break;
    		case MPL__XM_EFF_TREMOLO:
    			if (cell->param & 0xf0)
    			{
    				p_ch->tremolo_speed = param_x;
    			}
    			if (cell->param & 0xf)
    			{
    				p_ch->tremolo_depth = param_y;
    			}
    			break;
    		case MPL__XM_EFF_PAN:
    			p_ch->pan   = param;
    			p_ch->ctrl |= MPL__XM_CTRL_VOL;
    			break;
    		case MPL__XM_EFF_SMP_OFFSET:
    			p_ch->smp_offset = param << 8;
    			p_ch->ctrl      |= MPL__XM_CTRL_START;
    			break;
    		case MPL__XM_EFF_VOL_SLIDE:
    			if (param)
    			{
    				p_ch->vol_slide = param;
    			}
    			break;
    		case MPL__XM_EFF_POS_JUMP:
    			if (param < xm->length)
    			{
    				pl->pat_next = param;
    				pattern_jump = 1;
    			}
    			break;
    		case MPL__XM_EFF_VOL:
    			p_ch->vol   = param;
    			p_ch->ctrl |= MPL__XM_CTRL_VOL;
    			break;
    		case MPL__XM_EFF_PAT_BREAK:
    			pl->row_next  = param_x * 10 + param_y;
    			pattern_break = 1;
    			break;
    		case MPL__XM_EFF_MOD_EXT:
    			switch(param_x)
    			{
    			case MPL__XM_EXT_EFF_FINE_PORTA_UP:
    				if (param_y)
    				{
    					p_ch->fporta_up = param_y << 2;
    				}
    				p_ch->per -= p_ch->fporta_up;
    				break;
    			case MPL__XM_EXT_EFF_FINE_PORTA_DOWN:
    				if (param_y)
    				{
    					p_ch->fporta_down = param_y << 2;
    				}
    				p_ch->per += p_ch->fporta_down;
    				break;
    			case MPL__XM_EXT_EFF_GLISSANDO:
    				// *fart*
    				break;
    			case MPL__XM_EXT_EFF_VIB_WAVE:
    				p_ch->wave_control &= 0xf0;
    				p_ch->wave_control |= param_y;
    				break;
    			case MPL__XM_EXT_EFF_FINE_TUNE:
    				if (p_ch->p_smp)
    				{
    					pl->smp_fine_tune[p_ch->p_smp->index] = param_y;
    				}
    				break;
    			case MPL__XM_EXT_EFF_PAT_LOOP:
    				if (param_y == 0)
    				{
    					p_ch->loop_row = pl->row_cur;
    				}
    				else
    				{
    					if (!p_ch->loop_num)
    					{
    						p_ch->loop_num = param_y;
    					}
    					else
    					{
    						p_ch->loop_num--;
    					}
    					if (p_ch->loop_num)
    					{
    						pl->row_next = p_ch->loop_row - 1;
    					}
    				}
    				break;
    			case MPL__XM_EXT_EFF_TREMOLO_WAVE:
    				p_ch->wave_control &= 0xf;
    				p_ch->wave_control |= param_y << 4;
    				break;
    			case MPL__XM_EXT_EFF_PAN:
    				p_ch->pan   = param_y << 4;
    				p_ch->ctrl |= MPL__XM_CTRL_VOL;
    				break;
    			case MPL__XM_EXT_EFF_RETRIG:
    				break;
    			case MPL__XM_EXT_EFF_FINE_VOL_SLIDE_UP:
    				if (param_y)
    				{
    					p_ch->fvol_slide_up = param_y;
    				}
    				p_ch->vol  += p_ch->fvol_slide_up;
    				p_ch->ctrl |= MPL__XM_CTRL_VOL;
    				break;
    			case MPL__XM_EXT_EFF_FINE_VOL_SLIDE_DOWN:
    				if (param_y)
    				{
    					p_ch->fvol_slide_down = param_y;
    				}
    				p_ch->vol  -= p_ch->fvol_slide_up;
    				p_ch->ctrl |= MPL__XM_CTRL_VOL;
    				break;
    			case MPL__XM_EXT_EFF_NOTE_CUT:
    				break;
    			case MPL__XM_EXT_EFF_NOTE_DELAY:
    /*				p_ch->vol   = old_vol;
    				p_ch->pan   = old_pan;
    				p_ch->per   = old_per;
    				p_ch->ctrl &= ~(MPL__XM_CTRL_START|MPL__XM_CTRL_VOL|MPL__XM_CTRL_PER);*/
    				break;
    			case MPL__XM_EXT_EFF_PAT_DELAY:
    				pl->delay = param_y * pl->speed;
    				break;
    			default:
    				break;
    			}
    			break;
    		case MPL__XM_EFF_SPEED:
    			if (param < 32)
    			{
    				pl->speed = param;
    			}
    			else
    			{
    				pl->bpm        = param;
    				pl->ctrl      |= MPL__XM_PL_CTRL_BPM;
    			}
    			break;
    		case MPL__XM_EFF_GLOB_VOL:
    			pl->glob_vol = param;
    			pl->ctrl    |= MPL__XM_PL_CTRL_VOL;
    			break;
    		case MPL__XM_EFF_GLOB_VOL_SLIDE:
    			pl->glob_vol_slide = param;
    			pl->ctrl          |= MPL__XM_PL_CTRL_VOL;
    			break;
    		case MPL__XM_EFF_KEY_OFF:
    			break;
    		case MPL__XM_EFF_ENV_POS:
    			if (p_ch->p_inst)
    			{
    				if (p_ch->p_inst->vol_type & MPL__XM_ENV_ON)
    				{
    					p_ch->env_vol_tick = param;
    				}
    			}
    			break;
    		case MPL__XM_EFF_PAN_SLIDE:
    			if (param)
    			{
    				p_ch->pan_slide = param;
    			}
    			break;
    		case MPL__XM_EFF_RETRIG_VOL_SLIDE:
    			if (param)
    			{
    				p_ch->retrig_vol_slide = param;
    			}
    			break;
    		case MPL__XM_EFF_TREMOR:
    			if (param)
    			{
    				p_ch->tremor_spd = param;
    			}
    			do_tremor(p_ch);
    			break;
    		case MPL__XM_EFF_EXTRA_FINE_PORTA:
    			switch(param_x)
    			{
    			case 1:
    				if (param_y)
    				{
    					p_ch->efporta_up = param_y;
    				}
    				p_ch->per  -= p_ch->efporta_up;
    				p_ch->ctrl |= MPL__XM_CTRL_PER;
    				break;
    			case 2:
    				if (param_y)
    				{
    					p_ch->efporta_down = param_y;
    				}
    				p_ch->per  += p_ch->efporta_down;
    				p_ch->ctrl |= MPL__XM_CTRL_PER;
    				break;
    			default:
    				break;
    			}
    			break;
    		default:
    			break;
    		}
    no_effects:
    		if (p_ch->p_inst)
    		{
    			if (p_ch->p_inst->vol_type & MPL__XM_ENV_ON)
    			{
    				do_env_vol(p_ch);
    			}
    			else
    			{
    				if (p_ch->key_off)
    				{
    					p_ch->env_vol = 0;
    				}
    			}

    			if (p_ch->p_inst->pan_type & MPL__XM_ENV_ON)
    			{
    				do_env_pan(p_ch);
    			}

    			if (p_ch->key_off)
    			{
    				p_ch->fade_out_vol = clip_to(p_ch->fade_out_vol - p_ch->p_inst->vol_fade_out, 0, 65536);
    				p_ch->ctrl        |= MPL__XM_CTRL_VOL;
    			}
    		}

    		do_inst_vibrato(p_ch);
    	}

    	if (pattern_break && !pattern_jump)
    	{
    		pl->pat_next++;
    	}

    	if (!pattern_break && pattern_jump)
    	{
    		pl->row_next=0;
    	}

    	if (pl->row_next >= xm->pat_length[xm->order[pl->pat_cur]])
    	{
    		pl->row_next = 0;
    		pl->pat_next++;
    	}
    }

    void
    update_effects(mpl__mp_xm_t *pl)
    {
    	int ch;
    	mpl__xm_cell_t *row_cur, *cell;
    	mpl__xm_t *xm;
    	mpl__mp_xm_chan_t *p_ch;

    	xm = pl->xm;
    	row_cur = get_row(pl);

    	for(ch = 0; ch < xm->ch_num; ch++)
    	{
    		int param, param_x, param_y;

    		cell = &row_cur[ch];
    		p_ch = &pl->ch[ch];

    		p_ch->per_delta = 0;
    		p_ch->vol_delta = 0;

    		do_vol(pl, p_ch, cell->volume);

    		if (cell->effect == 0 && cell->param == 0)
    		{
    			goto no_effects;
    		}

    		param   = cell->param;
    		param_x = param >> 4;
    		param_y = param & 0xf;

    		switch(cell->effect)
    		{
    		case MPL__XM_EFF_ARPEGGIO:
    			switch(pl->tick_cur % 3)
    			{
    			case 1:
    				if (p_ch->p_smp)
    				{
    					if (xm->freq_table & MPL__XM_FREQ_TABLE_LINEAR)
    					{
    						p_ch->per_delta = param_x << 6;
    					}
    					else
    					{
    						p_ch->per_delta = note_to_period(p_ch->real_key + param_x, pl->smp_fine_tune[p_ch->p_smp->index]) - note_to_period(p_ch->real_key, pl->smp_fine_tune[p_ch->p_smp->index]);
    					}

    					p_ch->ctrl |= MPL__XM_CTRL_PER;
    				}
    				break;
    			case 2:
    				if (p_ch->p_smp)
    				{
    					if (xm->freq_table & MPL__XM_FREQ_TABLE_LINEAR)
    					{
    						p_ch->per_delta = param_y << 6;
    					}
    					else
    					{
    						p_ch->per_delta = note_to_period(p_ch->real_key + param_y, pl->smp_fine_tune[p_ch->p_smp->index]) - note_to_period(p_ch->real_key, pl->smp_fine_tune[p_ch->p_smp->index]);
    					}
    					p_ch->ctrl |= MPL__XM_CTRL_PER;
    				}
    				break;
    			default:
    				p_ch->ctrl |= MPL__XM_CTRL_PER;
    				break;
    			}
    			break;
    		case MPL__XM_EFF_PORTA_UP:
    			p_ch->per  -= p_ch->porta_up;
    			p_ch->ctrl |= MPL__XM_CTRL_PER;
    			break;
    		case MPL__XM_EFF_PORTA_DOWN:
    			p_ch->per  += p_ch->porta_down;
    			p_ch->ctrl |= MPL__XM_CTRL_PER;
    			break;
    		case MPL__XM_EFF_PORTA:
    			do_porta(p_ch);
    			break;
    		case MPL__XM_EFF_VIB:
    			do_vibrato(p_ch, 2, 1);
    			break;
    		case MPL__XM_EFF_PORTA_VOL_SLIDE:
    			do_porta(p_ch);
    			do_vol_slide(p_ch, p_ch->porta_vol_slide);
    			break;
    		case MPL__XM_EFF_VIB_VOL_SLIDE:
    			do_vibrato(p_ch, 2, 1);
    			do_vol_slide(p_ch, p_ch->vib_vol_slide);
    			break;
    		case MPL__XM_EFF_TREMOLO:
    			do_tremolo(p_ch);
    			break;
    		case MPL__XM_EFF_PAN:
    			break;
    		case MPL__XM_EFF_SMP_OFFSET:
    			break;
    		case MPL__XM_EFF_VOL_SLIDE:
    			do_vol_slide(p_ch, p_ch->vol_slide);
    			break;
    		case MPL__XM_EFF_POS_JUMP:
    			break;
    		case MPL__XM_EFF_VOL:
    			break;
    		case MPL__XM_EFF_PAT_BREAK:
    			break;
    		case MPL__XM_EFF_MOD_EXT:
    			switch(param & 0xf0)
    			{
    			case MPL__XM_EXT_EFF_FINE_PORTA_UP:
    				break;
    			case MPL__XM_EXT_EFF_FINE_PORTA_DOWN:
    				break;
    			case MPL__XM_EXT_EFF_GLISSANDO:
    				break;
    			case MPL__XM_EXT_EFF_VIB_WAVE:
    				break;
    			case MPL__XM_EXT_EFF_FINE_TUNE:
    				break;
    			case MPL__XM_EXT_EFF_PAT_LOOP:
    				break;
    			case MPL__XM_EXT_EFF_TREMOLO_WAVE:
    				break;
    			case MPL__XM_EXT_EFF_PAN:
    				break;
    			case MPL__XM_EXT_EFF_RETRIG:
    				if (!param_y)
    				{
    					return;
    				}
    				if (!(pl->tick_cur % param_y))
    				{
    					retrig(p_ch);
    				}
    				break;
    			case MPL__XM_EXT_EFF_FINE_VOL_SLIDE_UP:
    				break;
    			case MPL__XM_EXT_EFF_FINE_VOL_SLIDE_DOWN:
    				break;
    			case MPL__XM_EXT_EFF_NOTE_CUT:
    				if (pl->tick_cur == param_y)
    				{
    					p_ch->ctrl |= MPL__XM_CTRL_STOP;
    				}
    				break;
    			case MPL__XM_EXT_EFF_NOTE_DELAY:
    /*				if (pl->tick_cur == param_y)
    				{
    					if (p_ch->p_smp)
    					{
    						new_smp(p_ch);
    						do_vol(pl, p_ch, cell->volume);
    						p_ch->ctrl |= XM_CTRL_START|XM_CTRL_PER|XM_CTRL_VOL;
    					}
    				}
    				else
    				{
    					p_ch->ctrl &= ~(XM_CTRL_START|XM_CTRL_PER|XM_CTRL_VOL);
    				}*/
    				break;
    			case MPL__XM_EXT_EFF_PAT_DELAY:
    				break;
    			default:
    				break;
    			}
    			break;
    		case MPL__XM_EFF_SPEED:
    			break;
    		case MPL__XM_EFF_GLOB_VOL:
    			break;
    		case MPL__XM_EFF_GLOB_VOL_SLIDE:
    			param_x = pl->glob_vol_slide >> 4;
    			param_y = pl->glob_vol_slide & 0xf;
    			if (param_x)
    			{
    				pl->glob_vol += param_x;
    			}
    			else
    			{
    				if (param_y)
    				{
    					pl->glob_vol -= param_y;
    				}
    			}
    			pl->ctrl |= MPL__XM_PL_CTRL_VOL;
    			break;
    		case MPL__XM_EFF_KEY_OFF:
    			if (pl->tick_cur == param)
    			{
    				p_ch->key_off = 1;
    			}
    			break;
    		case MPL__XM_EFF_ENV_POS:
    			break;
    		case MPL__XM_EFF_PAN_SLIDE:
    			param_x = p_ch->pan_slide >> 4;
    			param_y = p_ch->pan_slide & 0xf;
    			if (param_x)
    			{
    				p_ch->pan += param_x;
    			}
    			else
    			{
    				if (param_y)
    				{
    					p_ch->pan -= param_y;
    				}
    			}
    			p_ch->ctrl |= MPL__XM_CTRL_VOL;
    			break;
    		case MPL__XM_EFF_RETRIG_VOL_SLIDE:
    			if (!(p_ch->retrig_vol_slide & 0xf))
    			{
    				break;
    			}
    			if (pl->tick_cur % (p_ch->retrig_vol_slide & 0xf))
    			{
    				break;
    			}

    			retrig(p_ch);

    			switch(p_ch->retrig_vol_slide & 0xf0)
    			{
    			case 0x10: p_ch->vol -= 1;	break;
    			case 0x90: p_ch->vol += 1; break;
    			case 0x20: p_ch->vol -= 2; break;
    			case 0xA0: p_ch->vol += 2; break;
    			case 0x30: p_ch->vol -= 4; break;
    			case 0xB0: p_ch->vol += 4; break;
    			case 0x40: p_ch->vol -= 8; break;
    			case 0xC0: p_ch->vol += 8; break;
    			case 0x50: p_ch->vol -= 16; break;
    			case 0xD0: p_ch->vol += 16; break;
    			case 0x60: p_ch->vol = (p_ch->vol << 1) / 3; break;
    			case 0xE0: p_ch->vol = (p_ch->vol * 3) >> 1; break;
    			case 0x70: p_ch->vol >>= 1; break;
    			case 0xF0: p_ch->vol <<= 1; break;
    			}

    			p_ch->ctrl |= MPL__XM_CTRL_VOL;

    			break;
    		case MPL__XM_EFF_TREMOR:
    			do_tremor(p_ch);
    			break;
    		case MPL__XM_EFF_EXTRA_FINE_PORTA:
    			break;
    		default:
    			break;
    		}

    no_effects:

    		if (p_ch->p_inst)
    		{
    			if (p_ch->key_off)
    			{
    				p_ch->fade_out_vol = clip_to(p_ch->fade_out_vol - p_ch->p_inst->vol_fade_out, 0, 65536);
    				p_ch->ctrl        |= MPL__XM_CTRL_VOL;
    			}

    			if (p_ch->p_inst->vol_type & MPL__XM_ENV_ON)
    			{
    				do_env_vol(p_ch);
    			}
    			else
    			{
    				if (p_ch->key_off)
    				{
    					p_ch->env_vol = 0;
    				}
    			}

    			if (p_ch->p_inst->pan_type & MPL__XM_ENV_ON)
    			{
    				do_env_pan(p_ch);
    			}
    		}

    		do_inst_vibrato(p_ch);
    	}
    }

    static void
    run_tick(mpl__mp_xm_t *pl, int param)
    {
    	if (!pl->xm->length)
    	{
    		return;
    	}

    	if (pl->tick_cur >= pl->speed)
    	{
    		pl->tick_cur = 0;

    		if (!pl->delay)
    		{
    			pl->pat_cur = pl->pat_next;
    			pl->row_cur	= pl->row_next;
    			update_row(pl);
    		}
    		else
    		{
    			pl->delay--;
    		}
    	}
    	else
    	{
    		update_effects(pl);
    	}

    	update_ctrl(pl);

    	pl->tick_cur++;
    }

    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    ///  interface  ////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////

    static int
    mp_cmd_reset(void *internal_data)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;
    	mpl__mp_xm_chan_t *p_ch;
    	int ch, inst, smp;

    	pl->bpm            = pl->xm->bpm;
    	pl->ctrl          |= MPL__XM_PL_CTRL_BPM;
    	pl->speed          = pl->xm->speed;
    	pl->tick_cur       = pl->speed;
    	pl->pat_cur        = 0;
    	pl->pat_next       = 0;
    	pl->row_cur        = 0;
    	pl->row_next       = 0;
    	pl->delay          = 0;
    	pl->glob_vol       = 64;
    	pl->glob_vol_slide = 0;
    	pl->delay          = 0;

    	mpl__mem_set_zero(pl->ch, sizeof(mpl__mp_xm_chan_t) * 32);

    	for(inst = 0; inst < pl->xm->inst_num; inst++)
    	{
    		for(smp = 0; smp < pl->xm->inst[inst].smp_num; smp++)
    		{
    			pl->smp_fine_tune[pl->xm->inst[inst].smp[smp].index] = pl->xm->inst[inst].smp[smp].finetune;
    		}
    	}

    	for(ch = 0; ch < 64; ch++)
    	{
    		p_ch = pl->ch + ch;

    		p_ch->pan = 0x80;
    		p_ch->key = MPL__XM_NO_NOTE;
    	}

    	if (pl->dev)
    	{
    		if (!pl->paused)
    		{
    			mpl__snd_mixer_pause(pl->mixer);

    			pl->paused = 1;
    		}

    		mpl__snd_mixer_stop(pl->mixer);

    		run_tick(pl, 0);
    	}

    	return 0;
    }

    static int
    mp_cmd_set_dev(void *internal_data, mpl__snd_dev_t *dev)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;
    	mpl__snd_mixer_opt_t opt;
    	mpl__snd_dev_output_t output;
    	mpl__snd_mixer_smp_t upload;
    	int inst, smp, cur;
    	mpl__xm_sample_t *p_smp;

    	if (pl->dev)
    	{
    		mpl__snd_dev_destroy_mixer(pl->dev, pl->mixer);

    		pl->dev = 0;
    		pl->mixer = 0;
    	}

    	if (!dev)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (mpl__snd_dev_get_output_options(dev, &output) < 0)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	opt.latency = MPL__SND_DEV_LATENCY_HIGH;
    	opt.ch_num  = pl->xm->ch_num;
    	opt.smp_num = pl->xm->smp_index_num;

    	if (mpl__snd_dev_create_mixer(dev, &pl->mixer, opt) < 0)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	pl->dev = dev;

    	for (cur = 0; cur < pl->xm->smp_index_num; cur++)
    	{
    		pl->smp_handle[cur] = -1;
    	}

    	for(inst = 0; inst < pl->xm->inst_num; inst++)
    	{
    		for(smp = 0; smp < pl->xm->inst[inst].smp_num; smp++)
    		{
    			p_smp = pl->xm->inst[inst].smp + smp;

    			if (p_smp->length < 4)
    			{
    				continue;
    			}

    			upload.format = p_smp->format & MPL__XM_SMP_16BIT ? MPL__SND_DEV_FMT_16BIT : MPL__SND_DEV_FMT_8BIT;
    			upload.channels = 1;
    			upload.freq = 8363;
    			upload.loop = p_smp->loop_begin;
    			upload.data = p_smp->data;

    			switch(p_smp->format & 3)
    			{
    			default:
    			case MPL__XM_SMP_NO_LOOP:
    				upload.loopmode = MPL__SND_DEV_FMT_NONLOOPING;
    				upload.length   = p_smp->length;
    				break;
    			case MPL__XM_SMP_LOOP:
    				upload.loopmode = MPL__SND_DEV_FMT_LOOPING;
    				upload.length   = p_smp->loop_end;
    				break;
    			case MPL__XM_SMP_BIDI_LOOP:
    				upload.loopmode = MPL__SND_DEV_FMT_BIDILOOPING;
    				upload.length   = p_smp->loop_end;
    				break;
    			}

    			upload.vol    = 1.0f;
    			upload.pan_lr = 0.5f;
    			upload.pan_fb = 0.5f;

    			pl->smp_handle[p_smp->index] = mpl__snd_mixer_upload_sample(pl->mixer, upload);

    			if (pl->smp_handle[p_smp->index] < 0)
    			{
    				mpl__snd_dev_destroy_mixer(pl->dev, pl->mixer);

    				pl->dev   = 0;
    				pl->mixer = 0;

    				return MPL__ERR_GENERIC;
    			}
    		}
    	}

    	pl->ctrl          |= MPL__XM_PL_CTRL_BPM;

    	if (pl->paused)
    	{
    		mpl__snd_mixer_pause(pl->mixer);
    	}

    	run_tick(pl, 0);

    	return 0;
    }

    static int
    mp_cmd_play(void *internal_data)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	if (!pl->dev)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	if (pl->paused)
    	{
    		mpl__snd_mixer_pause(pl->mixer);
    		pl->paused = 0;

    		return MPL__ERR_OK;
    	}

    	return MPL__ERR_GENERIC;
    }

    static int
    mp_cmd_stop(void *internal_data)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	if (!pl->dev)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	if (!pl->paused)
    	{
    		mpl__snd_mixer_pause(pl->mixer);
    		pl->paused = 1;

    		return MPL__ERR_OK;
    	}

    	return MPL__ERR_GENERIC;
    }

    static int
    mp_cmd_set_loop(void *internal_data, int loop)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	if (loop < 0 && loop != MPL__MP_LOOP_FOREVER)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	pl->loop = loop;

    	return MPL__ERR_OK;
    }

    static int
    mp_cmd_set_pos(void *internal_data, int pos)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;
    	int pat_next, row_next;
    	int cur = 0;

    	pat_next = pos >> 24;
    	row_next = pos & 0xfff;

    	if (pat_next < 0 || pat_next >= pl->xm->length)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (row_next < 0 || row_next >= pl->xm->pat_length[pat_next])
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	pl->pat_next = pat_next;
    	pl->row_next = row_next;

    	for(cur = 0; cur < pl->xm->ch_num; cur++)
    	{
    		pl->ch[cur].loop_num = 0;
    	}

    	return 0;
    }

    static int
    mp_cmd_get_pos(void *internal_data)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	return (pl->pat_cur << 24) + pl->row_cur;
    }

    static int
    mp_cmd_set_vol(void *internal_data, float32 vol)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	pl->vol = vol;

    	pl->glob_vol = clip_to(pl->glob_vol, 0, 64);

    	vol = pl->vol * pl->glob_vol * (1.0f / 64.0f);

    	mpl__snd_mixer_set_vol(pl->mixer, vol, 0.5f, 0.5f);

    	return 0;
    }

    static int
    mp_cmd_get_vol(void *internal_data, float32 *vol)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	*vol = pl->vol;

    	return 0;
    }

    static int
    mp_cmd_set_option(void *internal_data, char *option, char *value)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	return MPL__ERR_GENERIC;
    }

    static int
    mp_cmd_get_option(void *internal_data, char *option, char **value)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	return MPL__ERR_GENERIC;
    }

    static int
    mp_cmd_get_proc(void *internal_data, char *name, void_func_t *proc)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)internal_data;

    	return MPL__ERR_GENERIC;
    }

    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    ///  creation  /////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////

    int
    mpl__mp_xm_construct(mpl__xm_t *xm, mpl__mp_t *mp, mpl__msg_box_t *mb)
    {
    	mpl__mp_xm_t *pl;

    	if (mpl__mem_alloc(sizeof(mpl__mp_xm_t), (void**)&pl) <= MPL__ERR_GENERIC)
    	{
    		return MPL__ERR_NOMEM;
    	}

    	mpl__mem_set_zero(pl, sizeof(mpl__mp_xm_t));

    	pl->xm     = xm;
    	pl->vol    = 0.5f;
    	pl->mb     = mb;
    	pl->paused = 1;

    	mp_cmd_reset(pl);

    	mp->get_option = mp_cmd_get_option;
    	mp->get_pos    = mp_cmd_get_pos;
    	mp->get_proc   = mp_cmd_get_proc;
    	mp->get_vol    = mp_cmd_get_vol;
    	mp->play       = mp_cmd_play;
    	mp->reset      = mp_cmd_reset;
    	mp->set_dev    = mp_cmd_set_dev;
    	mp->set_loop   = mp_cmd_set_loop;
    	mp->set_option = mp_cmd_set_option;
    	mp->set_pos    = mp_cmd_set_pos;
    	mp->set_vol    = mp_cmd_set_vol;
    	mp->stop       = mp_cmd_stop;

    	mp->internal_data = pl;

    	return 0;
    }

    int
    mpl__mp_xm_destruct(mpl__mp_t *mp)
    {
    	mpl__mp_xm_t *pl = (mpl__mp_xm_t*)mp->internal_data;

    	if (pl->mixer)
    	{
    		mpl__snd_dev_destroy_mixer(pl->dev, pl->mixer);
    	}

    	mpl__mem_free(mp->internal_data);

    	return 0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/sys/critsect.c] - (907 bytes)

    #include <mpl/sys/critsect.h>
    #include <mpl/sys/mem.h>

    int
    mpl__cs_create(mpl__critical_section_t **cs)
    {
    	int result;

    	result = mpl__mem_alloc(sizeof(mpl__critical_section_t), (void**)cs);

    	if (result <= MPL__ERR_GENERIC)
    	{
    		return result;
    	}

    	result = mpl__cs_construct(*cs);

    	if (result <= MPL__ERR_GENERIC)
    	{
    		return result;
    	}

    	return 0;
    }

    int
    mpl__cs_destroy(mpl__critical_section_t *cs)
    {
    	mpl__cs_destruct(cs);
    	mpl__mem_free(cs);

    	return 0;
    }

    int
    mpl__cs_construct(mpl__critical_section_t *cs)
    {
    	InitializeCriticalSection(cs);

    	return 0;
    }

    int
    mpl__cs_destruct(mpl__critical_section_t *cs)
    {
    	DeleteCriticalSection(cs);

    	return 0;
    }

    int
    mpl__cs_enter(mpl__critical_section_t *cs)
    {
    	EnterCriticalSection(cs);

    	return 0;
    }

    int
    mpl__cs_leave(mpl__critical_section_t *cs)
    {
    	LeaveCriticalSection(cs);

    	return 0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/sys/msg_box.c] - (1,706 bytes)

    #include <mpl/sys/msg_box.h>
    #include <mpl/sys/mem.h>

    int
    mpl__msg_box_create(mpl__msg_box_t **mb, int max)
    {
    	int result;

    	result = mpl__mem_alloc(sizeof(mpl__msg_box_t), (void**)mb);

    	if (result <= MPL__ERR_GENERIC)
    	{
    		return result;
    	}

    	result = mpl__msg_box_construct(*mb, max);

    	if (result <= MPL__ERR_GENERIC)
    	{
    		mpl__mem_free(*mb);

    		return result;
    	}

    	return 0;
    }

    int
    mpl__msg_box_destroy(mpl__msg_box_t *mb)
    {
    	mpl__msg_box_destruct(mb);

    	mpl__mem_free(mb);

    	return 0;
    }

    int
    mpl__msg_box_construct(mpl__msg_box_t *mb, int max)
    {
    	int result;

    	result = mpl__mem_alloc(sizeof(mpl__msg_t) * max, (void**)&mb->msg);

    	if (result <= MPL__ERR_GENERIC)
    	{
    		return result;
    	}

    	mb->first = 0;
    	mb->last  = 0;
    	mb->cnt   = 0;
    	mb->max   = max;

    	result = mpl__cs_construct(&mb->cs);

    	if (result <= MPL__ERR_GENERIC)
    	{
    		mpl__mem_free(mb->msg);

    		return result;
    	}

    	return 0;
    }

    int
    mpl__msg_box_destruct(mpl__msg_box_t *mb)
    {
    	mpl__cs_destruct(&mb->cs);

    	mpl__mem_free(mb->msg);

    	return 0;
    }

    int
    mpl__msg_box_send(mpl__msg_box_t *mb, mpl__msg_t *msg)
    {
    	mpl__cs_enter(&mb->cs);

    	if (mb->cnt >= mb->max)
    	{
    		return MPL__ERR_MSG_BOX_FULL;
    	}

    	mb->msg[mb->last] = *msg;

    	if (++mb->last >= mb->max)
    	{
    		mb->last = 0;
    	}

    	mb->cnt++;

    	mpl__cs_leave(&mb->cs);

    	return 0;
    }

    int
    mpl__msg_box_receive(mpl__msg_box_t *mb, mpl__msg_t *msg)
    {
    	mpl__cs_enter(&mb->cs);

    	if (mb->cnt == 0)
    	{
    		return MPL__ERR_MSG_BOX_EMPTY;
    	}

    	*msg = mb->msg[mb->first];

    	if (++mb->first >= mb->max)
    	{
    		mb->first = 0;
    	}

    	mb->cnt--;

    	mpl__cs_leave(&mb->cs);

    	return 0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/sys/mem.c] - (1,440 bytes)

     /*
    	to do
    	-----

    	- statistics
    	- slab allocator? (a lot faster than standard malloc implementation)
    */

    #include <mpl/sys/mem.h>
    #include <mpl/sys/critsect.h>
    #include <stdlib.h>

    static mpl__critical_section_t l_cs;

    int
    mpl__mem_alloc(mpl__mem_size_t size, void **mem)
    {
    	void *memblock;

    //	mpl__cs_enter(&l_cs);
    	memblock = malloc(size);
    //	mpl__cs_leave(&l_cs);

    	if (!memblock)
    	{
    		return MPL__ERR_NOMEM;
    	}

    	*mem = memblock;

    	return 0;
    }

    int
    mpl__mem_get_size(mpl__mem_size_t *size, void *mem)
    {
    	return MPL__ERR_GENERIC;
    }

    int
    mpl__mem_resize(mpl__mem_size_t newsize, int onlyexpand, void **mem)
    {
    	return MPL__ERR_GENERIC;
    }

    int
    mpl__mem_free(void *mem)
    {
    	mpl__cs_enter(&l_cs);
    	free(mem);
    	mpl__cs_leave(&l_cs);

    	return 0;
    }

    int
    mpl__mem_copy(void *src, void *dst, mpl__mem_size_t size)
    {
    	char *s, *d;
    	int cnt;

    	s = (char*) src;
    	d = (char*) dst;

    	if ((mpl__mem_size_t)src > (mpl__mem_size_t)dst)
    	{
    		cnt = 0;

    		while(cnt < size)
    		{
    			d[cnt] = s[cnt];
    			cnt++;
    		}
    	}
    	else
    	{
    		while(size--)
    		{
    			d[size] = s[size];
    		}
    	}

    	return 0;
    }

    int
    mpl__mem_set_zero(void *mem, mpl__mem_size_t size)
    {
    	char *m;

    	m = (char*) mem;

    	while(size--)
    	{
    		m[size] = 0;
    	}

    	return 0;
    }

    int
    mpl__mem_init()
    {
    	if (mpl__cs_construct(&l_cs) < MPL__ERR_GENERIC)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	return 0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/mpl/mx_std.c] - (37,454 bytes)

    #include <mpl/sys/mem.h>
    #include <mpl/mx_std.h>
    #include <mpl/string.h>
    #include <mpl/dsp_std.h>

    // formats: mono/stereo, 8/16/24/32/float

    // to do
    // - better error checks
    // - more mixer functions? (four channels, etc.)
    // - lagrange interpolation?
    // - 24 bit mixing
    // - extensions: "EXT_FILTER EXT_REVERB EXT_CHORUS EXT_FX"
    // - quality improvement

    #define RAMPING 0.02f

    #define CHECK_FOR_ERRORS

    static int command_reset(void *internal);
    static int command_pause(void *internal);
    static int command_stop(void *internal);
    static int command_upload_sample(void *internal, mpl__snd_mixer_smp_t sample);
    static int command_destroy_sample(void *internal, int handle);
    static int command_set_sustain_loop(mpl__snd_mixer_t *sndmx, int handle, int begin, int end, int mode);
    static int command_end_sustain(mpl__snd_mixer_t *sndmx, int ch);
    static int command_set_vol(void *internal, float32 vol, float32 pan_lr, float32 pan_fb);
    static int command_get_vol(void *internal, float32 *vol, float32 *pan_lr, float32 *pan_fb);
    static int command_get_output_options(void *internal, mpl__snd_dev_output_t *opt);
    static int command_get_latency(void *internal);
    static int command_get_num_channels(void *internal);
    static int command_get_num_active_channels(void *internal);
    static int command_get_free_channel(void *internal);
    static int command_is_channel_active(void *internal, int ch);
    static int command_get_free_channel(void *internal);
    static int command_is_channel_active(void *internal, int ch);
    static int command_set_channel_vol(void *internal, int ch, float32 vol, float32 pan_lr, float32 pan_fb);
    static int command_set_channel_freq(void *internal, int ch, float32 freq);
    static int command_set_channel_pos(void *internal, int ch, float64 pos, int dir);
    static int command_play_channel(void *internal, int ch, int handle, float32 freq, float32 vol, float32 pan_lr, float32 pan_fb, float64 pos, int dir);
    static int command_stop_channel(void *internal, int ch);
    static int command_set_option(void *internal, char *option, char *value);
    static int command_get_option(void *internal, char *option, char **value);
    static int command_get_proc(void *internal, char *name, void_func_t *proc);
    static int command_set_call_back(void *internal, mpl__snd_call_back_t call_back);

    static int mixer_command_set_output_options(void *internal, mpl__snd_dev_output_t *opt, int latency);
    static int mixer_command_set_options(void *internal, mpl__mixer_opt_t *opt);
    static int mixer_command_get_options(void *internal, mpl__mixer_opt_t *opt);
    static int mixer_command_get_proc(void *internal, char *name, void_func_t *func);
    static int mixer_command_set_vol(void *internal, float32 vol, float32 pan_lr, float32 pan_fb);
    static int mixer_command_mix(void *internal, void *buffer, int length);
    static int mixer_command_get_num_active_channels(void *internal);

    ///////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////
    // no interpolation
    //#define __INTERPOLATE__(valm1, val0, val1, val2, t) (val0)
    // linear interpolation
    //#define __INTERPOLATE__(valm1, val0, val1, val2, t) (val0 + (val1 - val0) * t)
    // spline interpolation
    #define __INTERPOLATE__(valm1, val0, val1, val2, t) (((((3.0f * (val0 - val1) - valm1 + val2) * 0.5f) * t + (2.0f * val1 + valm1 - (5.0f * val0 + val2) * 0.5f)) * t + ((val1 - valm1) * 0.5f)) * t + val0)
    #define __RAMP___(a,b,c, d) {if (b) {a+=c;b--;if(!b) a=d;}}
    #define __RAMP__ {__RAMP___(p_ch->vol_left, p_ch->vol_left_ramp_num, p_ch->vol_left_ramp, p_ch->vol_left_dst) __RAMP___(p_ch->vol_right, p_ch->vol_right_ramp_num, p_ch->vol_right_ramp, p_ch->vol_right_dst) __RAMP___(p_ch->vol_center, p_ch->vol_center_ramp_num, p_ch->vol_center_ramp, p_ch->vol_center_dst)}

    void
    mix_inner_loop(mpl__mx_std_t *mx, int ch, float64 step, float32 *buf, int pos, int num)
    {
    	mpl__mx_std_smp_t *p_smp;
    	mpl__mx_std_ch_t *p_ch;
    	float32 *smp, tmp, pos_fract;
    	int pos_int;

    	p_ch  = mx->ch + ch;
    	p_smp = mx->smp + p_ch->smp;
    	smp   = (float32*)p_smp->smp.data;

    	switch(2 * (mx->output.channels - 1) + p_smp->smp.channels)
    	{
    	case 1:
    		while(num--)
    		{
    			pos_int   = (int)p_ch->pos;
    			pos_fract = (float32)(p_ch->pos - pos_int);

    			buf[pos++] += __INTERPOLATE__(smp[pos_int],     smp[pos_int + 1],
    				                          smp[pos_int + 2], smp[pos_int + 3],
    										  pos_fract) * p_ch->vol_center;

    			__RAMP__

    			p_ch->pos += step;
    		}
    		break;
    	case 2:
    		while(num--)
    		{
    			pos_int   = (int)p_ch->pos;
    			pos_fract = (float32)(p_ch->pos - pos_int);
    			pos_int <<= 1;

    			buf[pos]   += __INTERPOLATE__(smp[pos_int],     smp[pos_int + 2],
    				                          smp[pos_int + 4], smp[pos_int + 6],
    										  pos_fract) * p_ch->vol_left;

    			buf[pos++] += __INTERPOLATE__(smp[pos_int + 1], smp[pos_int + 3],
    				                          smp[pos_int + 5], smp[pos_int + 7],
    										  pos_fract) * p_ch->vol_right;

    			__RAMP__

    			p_ch->pos += step;
    		}
    		break;
    	case 3:
    		pos <<= 1;

    		while(num--)
    		{
    			pos_int   = (int)p_ch->pos;
    			pos_fract = (float32)(p_ch->pos - pos_int);

    			tmp = __INTERPOLATE__(smp[pos_int],     smp[pos_int + 1],
    				                  smp[pos_int + 2], smp[pos_int + 3],
    				   			      pos_fract);

    			buf[pos++] += tmp * p_ch->vol_left;
    			buf[pos++] += tmp * p_ch->vol_right;

    			__RAMP__

    			p_ch->pos += step;
    		}
    		break;
    	case 4:
    		pos <<= 1;

    		while(num--)
    		{
    			pos_int   = (int)p_ch->pos;
    			pos_fract = (float32)(p_ch->pos - pos_int);
    			pos_int <<= 1;

    			buf[pos++] += __INTERPOLATE__(smp[pos_int],     smp[pos_int + 2],
    				                          smp[pos_int + 4], smp[pos_int + 6],
    										  pos_fract) * p_ch->vol_left;

    			buf[pos++] += __INTERPOLATE__(smp[pos_int + 1], smp[pos_int + 3],
    				                          smp[pos_int + 5], smp[pos_int + 7],
    										  pos_fract) * p_ch->vol_right;

    			__RAMP__

    			p_ch->pos += step;
    		}
    		break;
    	}
    }

    #undef __INTERPOLATE__
    #undef __RAMP___
    #undef __RAMP__

    static void
    patch_smp(mpl__mx_std_ch_t *p_ch, mpl__mx_std_smp_t *p_smp)
    {
    	float32 *data;

    	if (p_ch->loop_mode != MPL__SND_DEV_FMT_LOOPING)
    	{
    		return;
    	}

    	data = (float32*)p_smp->smp.data;

    	if (p_ch->pos < p_ch->loop_beg)
    	{
    		switch(p_smp->smp.channels)
    		{
    		case 1:
    			p_ch->patch[0] = data[p_ch->loop_beg];
    			break;
    		case 2:
    			p_ch->patch[0] = data[p_ch->loop_beg];
    			p_ch->patch[1] = data[p_ch->loop_beg + 1];
    			break;
    		}
    	}
    	else
    	{
    		switch(p_smp->smp.channels)
    		{
    		case 1:
    			p_ch->patch[0] = data[p_ch->loop_beg];

    			data[p_ch->loop_beg] = data[p_ch->loop_end];
    			break;
    		case 2:
    			p_ch->patch[0] = data[p_ch->loop_beg];
    			p_ch->patch[1] = data[p_ch->loop_beg + 1];

    			data[p_ch->loop_beg]     = data[p_ch->loop_end];
    			data[p_ch->loop_beg + 1] = data[p_ch->loop_end + 1];
    			break;
    		}
    	}

    	switch(p_smp->smp.channels)
    	{
    	case 1:
    		p_ch->patch[1] = data[p_ch->loop_end + 1];
    		p_ch->patch[2] = data[p_ch->loop_end + 2];
    		p_ch->patch[3] = data[p_ch->loop_end + 3];

    		data[p_ch->loop_end + 1] = data[p_ch->loop_beg + 1];
    		data[p_ch->loop_end + 2] = data[p_ch->loop_beg + 2];
    		data[p_ch->loop_end + 3] = data[p_ch->loop_beg + 3];
    		break;
    	case 2:
    		p_ch->patch[2] = data[p_ch->loop_end * 2 + 2];
    		p_ch->patch[3] = data[p_ch->loop_end * 2 + 3];
    		p_ch->patch[4] = data[p_ch->loop_end * 2 + 4];
    		p_ch->patch[5] = data[p_ch->loop_end * 2 + 5];
    		p_ch->patch[6] = data[p_ch->loop_end * 2 + 6];
    		p_ch->patch[7] = data[p_ch->loop_end * 2 + 7];

    		data[p_ch->loop_end * 2 + 2] = data[p_ch->loop_beg * 2 + 2];
    		data[p_ch->loop_end * 2 + 3] = data[p_ch->loop_beg * 2 + 3];
    		data[p_ch->loop_end * 2 + 4] = data[p_ch->loop_beg * 2 + 4];
    		data[p_ch->loop_end * 2 + 5] = data[p_ch->loop_beg * 2 + 5];
    		data[p_ch->loop_end * 2 + 4] = data[p_ch->loop_beg * 2 + 6];
    		data[p_ch->loop_end * 2 + 5] = data[p_ch->loop_beg * 2 + 7];
    		break;
    	}
    }

    static void
    undo_patch(mpl__mx_std_ch_t *p_ch, mpl__mx_std_smp_t *p_smp)
    {
    	float32 *data;

    	if (p_ch->loop_mode != MPL__SND_DEV_FMT_LOOPING)
    	{
    		return;
    	}

    	data = (float32*)p_smp->smp.data;

    	switch(p_smp->smp.channels)
    	{
    	case 1:
    		data[p_ch->loop_beg]     = p_ch->patch[0];
    		data[p_ch->loop_end + 1] = p_ch->patch[1];
    		data[p_ch->loop_end + 2] = p_ch->patch[2];
    		data[p_ch->loop_end + 3] = p_ch->patch[3];
    		break;
    	case 2:
    		data[p_ch->loop_beg * 2]     = p_ch->patch[0];
    		data[p_ch->loop_beg * 2]     = p_ch->patch[1];
    		data[p_ch->loop_end * 2 + 2] = p_ch->patch[2];
    		data[p_ch->loop_end * 2 + 3] = p_ch->patch[3];
    		data[p_ch->loop_end * 2 + 4] = p_ch->patch[4];
    		data[p_ch->loop_end * 2 + 5] = p_ch->patch[5];
    		data[p_ch->loop_end * 2 + 6] = p_ch->patch[6];
    		data[p_ch->loop_end * 2 + 7] = p_ch->patch[7];
    		break;
    	}
    }

    static int
    calc_samples_left(mpl__mx_std_ch_t *p_ch, float64 fratio, float64 oofratio)
    {
    	int tmp;

    	if (p_ch->dir == MPL__SND_DEV_DIR_FORWARDS)
    	{
    		tmp = (int)((p_ch->loop_end - p_ch->pos) * oofratio);

    		if (p_ch->loop_mode != MPL__SND_DEV_FMT_BIDILOOPING)
    		{
    			if (tmp * fratio + p_ch->pos < p_ch->loop_end)
    			{
    				tmp++;
    			}
    		}
    	}
    	else
    	{
    		if (p_ch->pos < p_ch->loop_beg)
    		{
    			tmp =  (int)(p_ch->pos * oofratio);
    		}
    		else
    		{
    			tmp = (int)((p_ch->pos - p_ch->loop_beg) * oofratio);
    		}
    	}

    	if (tmp < 0)
    	{
    		tmp = 0;
    	}

    	return tmp;
    }

    static int
    fix_loop(mpl__mx_std_ch_t *p_ch, float64 *step, float64 fratio, float64 oofratio)
    {
    	if (p_ch->loop_mode == MPL__SND_DEV_FMT_NONLOOPING)
    	{
    		return 0;
    	}

    	if (p_ch->loop_mode == MPL__SND_DEV_FMT_LOOPING)
    	{
    		while(!calc_samples_left(p_ch, fratio, oofratio))
    		{
    			p_ch->pos -= p_ch->loop_end - p_ch->loop_beg;
    		}

    		if ((int)p_ch->pos < 0)
    		{

    			p_ch->pos += fratio;
    		}

    		return 1;
    	}

    	if (p_ch->loop_mode == MPL__SND_DEV_FMT_BIDILOOPING)
    	{
    		*step     = - *step;
    		p_ch->dir = (~p_ch->dir) & 1;

    		return 1;
    	}

    	return 0;
    }

    #define PAN2VOL_LEFT(pan) ((pan) <= 0.5f ? 1.0f : (1.0f - (pan)) * 2.0f)
    #define PAN2VOL_RIGHT(pan) ((pan) >= 0.5f ? 1.0f : (pan) * 2.0f)

    static void
    mix_channel(mpl__mx_std_t *mx, int ch, float32 *buf, i32 buf_pos, i32 num)
    {
    	i32 samples_left, cnt;
    	float64 fratio, oofratio, step;
    	float32 vol;
    	mpl__mx_std_smp_t *p_smp;
    	mpl__mx_std_ch_t *p_ch;

    	p_ch  = mx->ch + ch;
    	p_smp = mx->smp + p_ch->smp;

    	fratio   = p_ch->freq / mx->output.freq;
    	oofratio =          1 / fratio;

    	step      = fratio * (p_ch->dir == MPL__SND_DEV_DIR_FORWARDS ? 1 : -1);

    	if (ch < mx->ch_num)
    	{
    		vol                  = p_smp->smp.vol * p_ch->vol * mx->vol_global * mx->vol_local;
    		p_ch->vol_left_dst   = vol * PAN2VOL_LEFT(p_ch->pan_lr + p_smp->smp.pan_lr + mx->pan_lr_global + mx->pan_lr_local - 1.5f);
    		p_ch->vol_right_dst  = vol * PAN2VOL_RIGHT(p_ch->pan_lr + p_smp->smp.pan_lr + mx->pan_lr_global + mx->pan_lr_local - 1.5f);
    		p_ch->vol_center_dst = vol;
    	}
    	else
    	{
    		p_ch->vol_left_dst   = 0;
    		p_ch->vol_right_dst  = 0;
    		p_ch->vol_center_dst = 0;
    	}

    	if (p_ch->vol_left_dst != p_ch->vol_left)
    	{
    		if (p_ch->vol_left_dst > p_ch->vol_left)
    		{
    			p_ch->vol_left_ramp = mx->ramp;
    			p_ch->vol_left_ramp_num = (int)((p_ch->vol_left_dst - p_ch->vol_left) / mx->ramp);
    		}
    		else
    		{
    			p_ch->vol_left_ramp = -mx->ramp;
    			p_ch->vol_left_ramp_num = (int)((p_ch->vol_left - p_ch->vol_left_dst) / mx->ramp);
    		}
    	}

    	if (p_ch->vol_right_dst != p_ch->vol_right)
    	{
    		if (p_ch->vol_right_dst > p_ch->vol_right)
    		{
    			p_ch->vol_right_ramp = mx->ramp;
    			p_ch->vol_right_ramp_num = (int)((p_ch->vol_right_dst - p_ch->vol_right) / mx->ramp);
    		}
    		else
    		{
    			p_ch->vol_right_ramp = -mx->ramp;
    			p_ch->vol_right_ramp_num = (int)((p_ch->vol_right - p_ch->vol_right_dst) / mx->ramp);
    		}
    	}

    	if (p_ch->vol_center_dst != p_ch->vol_center)
    	{
    		if (p_ch->vol_center_dst > p_ch->vol_center)
    		{
    			p_ch->vol_center_ramp = mx->ramp;
    			p_ch->vol_center_ramp_num = (int)((p_ch->vol_center_dst - p_ch->vol_center) / mx->ramp);
    		}
    		else
    		{
    			p_ch->vol_center_ramp = -mx->ramp;
    			p_ch->vol_center_ramp_num = (int)((p_ch->vol_center - p_ch->vol_center_dst) / mx->ramp);
    		}
    	}

    	cnt = num;

    	while(cnt)
    	{
    		samples_left = calc_samples_left(p_ch, fratio, oofratio);

    		if (samples_left == 0)
    		{
    			if (!fix_loop(p_ch, &step, fratio, oofratio))
    			{
    				p_ch->playing = 0;

    				return;
    			}

    			samples_left = calc_samples_left(p_ch, fratio, oofratio);
    		}

    		if (samples_left == 0)
    		{
    			p_ch->playing = 0;

    			return;
    		}

    		samples_left = samples_left < cnt ? samples_left : cnt;

    		if (samples_left < 0)
    		{
    			samples_left=0;
    		}

    		patch_smp(p_ch, p_smp);
    		mix_inner_loop(mx, ch, step, buf, buf_pos, samples_left);
    		undo_patch(p_ch, p_smp);

    		if (p_ch->vol_left == 0 && p_ch->vol_right == 0 &&
    			ch >= mx->ch_num)
    		{
    			p_ch->playing = 0;

    			return;
    		}

    		cnt     -= samples_left;
    		buf_pos += samples_left;
    	}
    }

    static void
    filter_dc(mpl__mx_std_t *mx, float32 *buf, int length)
    {
    	if(mx->output.channels > 1)
    	{
    		while(length--)
    		{
    			mx->dc_spd[0] = mx->dc_spd[0] + (*buf - mx->dc_pos[0]) * 0.000004567f;
    			mx->dc_pos[0] = mx->dc_pos[0] + mx->dc_spd[0];
    			*buf          = *buf - mx->dc_pos[0];
    			buf++;
    			mx->dc_spd[1] = mx->dc_spd[1] + (*buf - mx->dc_pos[1]) * 0.000004567f;
    			mx->dc_pos[1] = mx->dc_pos[1] + mx->dc_spd[1];
    			*buf          = *buf - mx->dc_pos[1];
    			buf++;
    		}
    	}
    	else
    	{
    		while(length--)
    		{
    			mx->dc_spd[0] = mx->dc_spd[0] + (*buf - mx->dc_pos[0]) * 0.000004567f;
    			mx->dc_pos[0] = mx->dc_pos[0] + mx->dc_spd[0];
    			*buf          = *buf - mx->dc_pos[0];
    			buf++;
    		}

    		mx->dc_spd[1] = mx->dc_spd[0];
    		mx->dc_pos[1] = mx->dc_pos[0];
    	}
    }

    #undef PAN2VOL_LEFT
    #undef PAN2VOL_RIGHT

    static void
    quantize(float32 *src, void *dest, int length, int format)
    {
    	i32 tmp_i32;
    	i64 tmp_i64;

    	switch(format)
    	{
    	case MPL__SND_DEV_FMT_8BIT:
    		while(length--)
    		{
    			tmp_i32 = (i32)(src[length] * 128.0f);

    			if (tmp_i32 < -128) tmp_i32 = -125;
    			if (tmp_i32 > 127) tmp_i32 = 125;

    			((i8*)dest)[length] = (i8)tmp_i32;
    		}
    		break;
    	case MPL__SND_DEV_FMT_16BIT:
    		while(length--)
    		{
    			tmp_i32 = (i32)(src[length] * 32768.0f);

    			if (tmp_i32 < -32768) tmp_i32 = -32760;
    			if (tmp_i32 > 32767) tmp_i32 = 32760;

    			((i16*)dest)[length] = (i16)tmp_i32;
    		}
    		break;
    	case MPL__SND_DEV_FMT_24BIT:
    		// to do
    		break;
    	case MPL__SND_DEV_FMT_32BIT:
    		while(length--)
    		{
    			tmp_i64 = (i64)(src[length] * 2147483648.0f);

    			if (tmp_i64 < -(i64)2147483648) tmp_i64 = -(i64)2147483640;
    			if (tmp_i64 > 2147483647)       tmp_i64 = 2147483640;

    			((i32*)dest)[length] = (i32)tmp_i64;
    		}
    		break;
    	case MPL__SND_DEV_FMT_FLOAT_32BIT:
    		while(length--)
    		{
    			((float32*)dest)[length] = src[length];
    		}
    		break;
    	}
    }

    ///////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////

    static int
    command_reset(void *internal)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	int smp, ch;

    	for(ch = 0; ch < mx->ch_num * 2; ch++)
    	{
    		mx->ch[ch].playing = 0;
    	}

    	for(smp = 0; smp < mx->smp_num; smp++)
    	{
    		if (mx->smp[smp].smp.data)
    		{
    			mpl__mem_free(mx->smp[smp].smp.data);
    		}

    		mx->smp[smp].exists = 0;
    	}

    	mx->paused = 0;

    	return 0;
    }

    static int
    command_pause(void *internal)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	mx->paused ^= 1;

    	return 0;
    }

    static int
    command_stop(void *internal)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	int ch;

    	for(ch = 0; ch < mx->ch_num; ch++)
    	{
    		mx->ch[ch + mx->ch_num] = mx->ch[ch];
    		mx->ch[ch].playing      = 0;
    	}

    	return 0;
    }

    static int
    command_upload_sample(void *internal, mpl__snd_mixer_smp_t sample)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	int smp, size;
    	float32 *data;

    	for(smp = 0; smp < mx->smp_num; smp++)
    	{
    		if (!mx->smp[smp].exists) break;
    	}

    	if (smp == mx->smp_num)
    	{
    		return MPL__ERR_GENERIC;
    	}

    #ifdef CHECK_FOR_ERRORS

    	if (sample.channels != 1 &&
    		sample.channels != 2)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (sample.format < MPL__SND_DEV_FMT_8BIT || sample.format > MPL__SND_DEV_FMT_FLOAT_32BIT)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (sample.loopmode != MPL__SND_DEV_FMT_NONLOOPING &&
    		sample.loopmode != MPL__SND_DEV_FMT_LOOPING    &&
    		sample.loopmode != MPL__SND_DEV_FMT_BIDILOOPING)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (sample.length == 0)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (sample.loopmode != MPL__SND_DEV_FMT_NONLOOPING && sample.loop >= sample.length)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (sample.pan_fb < 0.0f || sample.pan_fb > 1.0f ||
    		sample.pan_lr < 0.0f || sample.pan_fb > 1.0f)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	size = sizeof(float32) * sample.channels;

    	mx->smp[smp].smp = sample;

    	mx->smp[smp].sus_loop_beg  = sample.loop;
    	mx->smp[smp].sus_loop_end  = sample.length;
    	mx->smp[smp].sus_loop_mode = sample.loopmode;

    	if (mpl__mem_alloc(size * (sample.length + 4), &mx->smp[smp].smp.data) <= MPL__ERR_GENERIC)
    	{
    		return MPL__ERR_NOMEM;
    	}

    	data = (float32*) mx->smp[smp].smp.data;

    	if (mpl__dsp_conv_format(sample.data, data + sample.channels,
    		sample.format, MPL__SND_DEV_FMT_FLOAT_32BIT, sample.length,
    		sample.channels, 1.0f) < MPL__ERR_OK)
    	{
    		mpl__mem_free((void*)data);

    		return MPL__ERR_GENERIC;
    	}

    	switch(sample.channels)
    	{
    	case 1:
    		data[0]                 = data[1];
    		data[sample.length + 1] = data[sample.length];
    		data[sample.length + 2] = data[sample.length];
    		data[sample.length + 3] = data[sample.length];
    		break;
    	case 2:
    		data[0]                 = data[2];
    		data[1]                 = data[3];
    		data[sample.length * 2 + 2] = data[sample.length * 2];
    		data[sample.length * 2 + 3] = data[sample.length * 2 + 1];
    		data[sample.length * 2 + 4] = data[sample.length * 2];
    		data[sample.length * 2 + 5] = data[sample.length * 2 + 1];
    		data[sample.length * 2 + 6] = data[sample.length * 2];
    		data[sample.length * 2 + 7] = data[sample.length * 2 + 1];
    		break;
    	}

    	mx->smp[smp].exists = 1;

    	return smp;
    }

    static int
    command_destroy_sample(void *internal, int handle)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	int ch;

    #ifdef CHECK_FOR_ERRORS

    	if (handle < 0 || handle >= mx->smp_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (!mx->smp[handle].exists)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	for(ch = 0; ch < mx->ch_num * 2; ch++)
    	{
    		if (mx->ch[ch].playing && mx->ch[ch].smp == handle)
    		{
    			return MPL__ERR_BAD_PARAM;
    		}
    	}
    #endif

    	mpl__mem_free(mx->smp[handle].smp.data);

    	mx->smp[handle].exists = 0;

    	return 0;
    }

    static int
    command_set_sustain_loop(mpl__snd_mixer_t *sndmx, int handle, int begin, int end, int mode)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) sndmx->internal_data;
    	mpl__mx_std_smp_t *smp;

    #ifdef CHECK_FOR_ERRORS

    	if (handle < 0 || handle >= mx->smp_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	smp = mx->smp + handle;

    	if (!smp->exists)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (end > smp->smp.length)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	smp->sus_loop_beg  = begin;
    	smp->sus_loop_end  = end;
    	smp->sus_loop_mode = mode;

    	return 0;
    }

    static int
    command_end_sustain(mpl__snd_mixer_t *sndmx, int ch)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) sndmx->internal_data;
    	mpl__mx_std_smp_t *smp;

    #ifdef CHECK_FOR_ERRORS

    	if (ch < 0 || ch >= mx->ch_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (!mx->ch[ch].playing)
    	{
    		return MPL__ERR_GENERIC;
    	}

    	smp = &mx->smp[mx->ch[ch].smp];

    #endif

    	mx->ch[ch].loop_beg  = smp->smp.loop;
    	mx->ch[ch].loop_end  = smp->smp.length;
    	mx->ch[ch].loop_mode = smp->smp.loopmode;

    	return 0;
    }

    static int
    command_set_vol(void *internal, float32 vol, float32 pan_lr, float32 pan_fb)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    #ifdef CHECK_FOR_ERRORS
    	if (pan_lr < 0.0f || pan_lr > 1.0f ||
    		pan_fb < 0.0f || pan_fb > 1.0f)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}
    #endif

    	mx->vol_local    = vol;
    	mx->pan_lr_local = pan_lr;
    	mx->pan_fb_local = pan_fb;

    	return 0;
    }

    static int
    command_get_vol(void *internal, float32 *vol, float32 *pan_lr, float32 *pan_fb)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	*vol    = mx->vol_local;
    	*pan_lr = mx->pan_lr_local;
    	*pan_fb = mx->pan_fb_local;

    	return 0;
    }

    static int
    command_get_output_options(void *internal, mpl__snd_dev_output_t *opt)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	*opt = mx->output;

    	return 0;
    }

    static int
    command_get_latency(void *internal)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	return mx->latency;
    }

    static int
    command_get_num_channels(void *internal)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	return mx->ch_num;
    }

    static int
    command_get_num_active_channels(void *internal)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	int ch, num;

    	num = 0;

    	for(ch = 0; ch < mx->ch_num; ch++)
    	{
    		if (mx->ch[ch].playing)
    		{
    			num++;
    		}
    	}

    	return num;
    }

    static int
    command_get_free_channel(void *internal)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	int ch;

    	for(ch = 0; ch < mx->ch_num; ch++)
    	{
    		if (!mx->ch[ch].playing)
    		{
    			return ch;
    		}
    	}

    	return MPL__ERR_GENERIC;
    }

    static int
    command_is_channel_active(void *internal, int ch)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    #ifdef CHECK_FOR_ERRORS

    	if (ch < 0 || ch >= mx->ch_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	return mx->ch[ch].playing != 0;
    }

    static int
    command_set_channel_vol(void *internal, int ch, float32 vol, float32 pan_lr, float32 pan_fb)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    #ifdef CHECK_FOR_ERRORS

    	if (ch < 0 || ch >= mx->ch_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (!mx->ch[ch].playing)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (pan_lr < 0.0f || pan_lr > 1.0f ||
    		pan_fb < 0.0f || pan_fb > 1.0f)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	mx->ch[ch].vol    = vol;
    	mx->ch[ch].pan_lr = pan_lr;

    	return 0;
    }

    static int
    command_set_channel_freq(void *internal, int ch, float32 freq)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    #ifdef CHECK_FOR_ERRORS

    	if (ch < 0 || ch >= mx->ch_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (!mx->ch[ch].playing)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (freq <= 0 || freq > 1000000)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	mx->ch[ch].freq = freq;

    	return -1;
    }

    static int
    command_set_channel_pos(void *internal, int ch, float64 pos, int dir)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    #ifdef CHECK_FOR_ERRORS

    	if (ch < 0 || ch >= mx->ch_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (!mx->ch[ch].playing)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (dir != MPL__SND_DEV_DIR_FORWARDS || dir != MPL__SND_DEV_DIR_BACKWARDS)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (pos < 0 || pos >= mx->ch[ch].loop_end)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	mx->ch[ch + mx->ch_num] = mx->ch[ch];

    	mx->ch[ch].pos        = pos;
    	mx->ch[ch].dir        = dir;
    	mx->ch[ch].vol_left   = 0;
    	mx->ch[ch].vol_right  = 0;
    	mx->ch[ch].vol_center = 0;

    	return 0;
    }

    static int
    command_play_channel(void *internal, int ch, int handle, float32 freq, float32 vol, float32 pan_lr, float32 pan_fb, float64 pos, int dir)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	mpl__mx_std_smp_t *smp;

    #ifdef CHECK_FOR_ERRORS

    	if (ch < 0 || ch >= mx->ch_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (handle < 0 || handle >= mx->smp_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	smp = mx->smp + handle;

    	if (!smp->exists)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (freq != -1 && (freq < 1 || freq > 1000000))
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (dir != -1 && dir != MPL__SND_DEV_DIR_FORWARDS && dir != MPL__SND_DEV_DIR_BACKWARDS)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (pan_lr < 0.0f || pan_lr > 1.0f ||
    		pan_fb < 0.0f || pan_fb > 1.0f)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (pos < 0 || pos >= smp->sus_loop_end)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	mx->ch[ch + mx->ch_num] = mx->ch[ch];

    	mx->ch[ch].pos        = pos;
    	mx->ch[ch].dir        = dir;
    	mx->ch[ch].smp        = handle;
    	mx->ch[ch].freq       = freq == -1 ? mx->smp[handle].smp.freq : freq;
    	mx->ch[ch].vol        = vol;
    	mx->ch[ch].pan_lr     = pan_lr;
    	mx->ch[ch].vol_left   = 0;
    	mx->ch[ch].vol_right  = 0;
    	mx->ch[ch].vol_center = 0;
    	mx->ch[ch].loop_beg   = smp->sus_loop_beg;
    	mx->ch[ch].loop_end   = smp->sus_loop_end;
    	mx->ch[ch].loop_mode  = smp->sus_loop_mode;
    	mx->ch[ch].playing    = 1;

    	return 0;
    }

    static int
    command_stop_channel(void *internal, int ch)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    #ifdef CHECK_FOR_ERRORS

    	if (ch < 0 || ch >= mx->ch_num)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	mx->ch[ch + mx->ch_num] = mx->ch[ch];
    	mx->ch[ch].playing      = 0;

    	return 0;
    }

    static int
    command_set_option(void *internal, char *option, char *value)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	return MPL__ERR_BAD_PARAM;
    }

    static int
    command_get_option(void *internal, char *option, char **value)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	if (mpl__string_cmp_char(option, "ID") == MPL__STRING_EQUAL)
    	{
    		*value = "standard mixer";

    		return 0;
    	}

    	if (mpl__string_cmp_char(option, "VERSION") == MPL__STRING_EQUAL)
    	{
    		*value = "0.01";

    		return 0;
    	}

    	if (mpl__string_cmp_char(option, "AUTHOR") == MPL__STRING_EQUAL)
    	{
    		*value = "";

    		return 0;
    	}

    	if (mpl__string_cmp_char(option, "EXTENSIONS") == MPL__STRING_EQUAL)
    	{
    		*value = "EXT_SUSTAIN_LOOP";

    		return 0;
    	}

    	return MPL__ERR_BAD_PARAM;
    }

    static int
    command_get_proc(void *internal, char *name, void_func_t *proc)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	if (mpl__string_cmp_char(name, MPL__FUNC_SND_MIXER_SET_SUSTAIN_LOOP) == MPL__STRING_EQUAL)
    	{
    		*proc = (void_func_t)command_set_sustain_loop;
    		return 1;
    	}

    	if (mpl__string_cmp_char(name, MPL__FUNC_SND_MIXER_END_SUSTAIN) == MPL__STRING_EQUAL)
    	{
    		*proc = (void_func_t)command_end_sustain;

    		return 0;
    	}

    	return MPL__ERR_BAD_PARAM;
    }

    static int
    command_set_call_back(void *internal, mpl__snd_call_back_t call_back)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	mx->call_back        = call_back;

    	mx->count_down_frac += mx->call_back.period * mx->output.freq * 0.001;
    	mx->count_down       = (int)(mx->count_down_frac);
    	mx->count_down_frac -= mx->count_down;

    	return 0;
    }

    ///////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////

    static int
    mixer_command_set_output_options(void *internal, mpl__snd_dev_output_t *opt, int latency)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    #ifdef CHECK_FOR_ERRORS

    	if (opt->channels != 1 &&
    		opt->channels != 2)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (opt->format < MPL__SND_DEV_FMT_8BIT || opt->format > MPL__SND_DEV_FMT_FLOAT_32BIT)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    	if (opt->latency != MPL__SND_DEV_LATENCY_HIGH && opt->latency != MPL__SND_DEV_LATENCY_HIGH)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	mx->dc_spd[0]     = 0;
    	mx->dc_pos[0]     = 0;
    	mx->dc_spd[1]     = 0;
    	mx->dc_pos[1]     = 0;

    	mx->output  = *opt;
    	mx->latency = latency;

    	mx->ramp    = 1.0f / (opt->freq * RAMPING);

    	mx->count_down = (int)(mx->count_down * opt->freq / mx->output.freq);

    	return 0;
    }

    static int
    mixer_command_set_options(void *internal, mpl__mixer_opt_t *opt)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	mpl__mx_std_ch_t *ch=0;
    	mpl__mx_std_smp_t *smp=0;

    	if (opt->ch_num != -1)
    	{
    		int cur;

    		if (opt->ch_num < 1 || opt->ch_num > 256)
    		{
    			return MPL__ERR_BAD_PARAM;
    		}

    		for(cur = 0; cur < mx->ch_num; cur++)
    		{
    			if (mx->ch[cur].playing)
    			{
    				return MPL__ERR_GENERIC;
    			}
    		}

    	}

    	if (opt->smp_num != -1)
    	{
    		int cur;

    		if (opt->smp_num < 1 || opt->smp_num > 256)
    		{
    			return MPL__ERR_BAD_PARAM;
    		}

    		for(cur = 0; cur < mx->smp_num; cur++)
    		{
    			if (mx->smp[cur].exists)
    			{
    				return MPL__ERR_GENERIC;
    			}
    		}
    	}

    	if (opt->mem_usage != -1)
    	{
    		if (opt->mem_usage != MPL__MX_MEM_AGGRESSIVE && opt->mem_usage != MPL__MX_MEM_LOW)
    		{
    			return MPL__ERR_BAD_PARAM;
    		}
    	}

    	if (opt->qual != -1)
    	{
    		if (opt->qual != MPL__MX_HQ && opt->qual != MPL__MX_LQ)
    		{
    			return MPL__ERR_BAD_PARAM;
    		}

    	}

    	if (opt->smp_num != -1)
    	{
    		if (mpl__mem_alloc(opt->smp_num * sizeof(mpl__mx_std_smp_t), (void**)&smp) <= MPL__ERR_GENERIC)
    		{
    			return MPL__ERR_NOMEM;
    		}

    		mpl__mem_set_zero(smp, opt->smp_num * sizeof(mpl__mx_std_smp_t));
    	}

    	if (opt->ch_num != -1)
    	{
    		if (mpl__mem_alloc(opt->ch_num * 2 * sizeof(mpl__mx_std_ch_t), (void**)&ch) <= MPL__ERR_GENERIC)
    		{
    			if (smp)
    			{
    				mpl__mem_free(smp);
    			}

    			return MPL__ERR_NOMEM;
    		}

    		mpl__mem_set_zero(ch, opt->ch_num * 2 * sizeof(mpl__mx_std_ch_t));
    	}

    	if (opt->ch_num != -1)
    	{
    		int cur;

    		mpl__mem_free(mx->ch);

    		mx->ch     = ch;
    		mx->ch_num = opt->ch_num;

    		for(cur = 0; cur < mx->ch_num * 2; cur++)
    		{
    			mx->ch[cur].playing = 0;
    		}
    	}

    	if (opt->smp_num != -1)
    	{
    		int cur;

    		for(cur = 0; cur < mx->smp_num; cur++)
    		{
    			if (mx->smp[cur].exists && mx->smp[cur].smp.data)
    			{
    				mpl__mem_free(mx->smp[cur].smp.data);
    			}
    		}

    		mpl__mem_free(mx->smp);

    		mx->smp     = smp;
    		mx->smp_num = opt->smp_num;

    		for(cur = 0; cur < mx->smp_num; cur++)
    		{
    			mx->smp[cur].exists = 0;
    		}
    	}

    	if (opt->mem_usage != -1)
    	{
    		mx->mem_usage = opt->mem_usage;
    	}

    	if (opt->qual != -1)
    	{

    		mx->qual = opt->qual;
    	}

    	return 0;
    }

    static int
    mixer_command_get_options(void *internal, mpl__mixer_opt_t *opt)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	opt->ch_num    = mx->ch_num;
    	opt->smp_num   = mx->smp_num;
    	opt->mem_usage = mx->mem_usage;
    	opt->qual      = mx->qual;

    	return 0;
    }

    static int
    mixer_command_get_proc(void *internal, char *name, void_func_t *func)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	return MPL__ERR_BAD_PARAM;
    }

    static int
    mixer_command_set_vol(void *internal, float32 vol, float32 pan_lr, float32 pan_fb)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    #ifdef CHECK_FOR_ERRORS

    	if (pan_lr < 0.0f || pan_lr > 1.0f ||
    		pan_fb < 0.0f || pan_fb > 1.0f)
    	{
    		return MPL__ERR_BAD_PARAM;
    	}

    #endif

    	mx->vol_global    = vol;
    	mx->pan_lr_global = pan_lr;
    	mx->pan_fb_global = pan_fb;

    	return 0;
    }

    static int
    mixer_command_mix(void *internal, void *buffer, int length)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	mpl__mx_std_ch_t *ch;
    	mpl__mx_std_smp_t *smp;
    	float32 *mix_buf;
    	int mix_buf_size, mix_buf_pos, cnt, gap_size;

    	mix_buf_size = mx->output.channels * length;

    //	bad (and slow)
    	if (mpl__mem_alloc(sizeof(float32) * mix_buf_size, (void**)&mix_buf) <= MPL__ERR_GENERIC)
    	{
    		return MPL__ERR_NOMEM;
    	}

    	mix_buf_pos = 0;

    	for(cnt = 0; cnt < mix_buf_size ; cnt++)
    	{
    		mix_buf[cnt] = 0;
    	}

    	if (mx->paused)
    	{
    		goto convert;
    	}

    	while(mix_buf_pos < length)
    	{
    		gap_size = length - mix_buf_pos;

    		if (mx->call_back.func)
    		{
    			if (!mx->count_down)
    			{
    				mx->call_back.func(mx->call_back.data, mx->call_back.param);

    				mx->count_down_frac += mx->call_back.period * mx->output.freq * 0.001;
    				mx->count_down       = (int)(mx->count_down_frac);
    				mx->count_down_frac -= mx->count_down;
    			}

    			gap_size = gap_size < mx->count_down ? gap_size : mx->count_down;
    		}

    		for(cnt = 0; cnt < mx->ch_num * 2; cnt++)
    		{
    			ch = mx->ch + cnt;

    			if (!ch->playing)
    			{
    				continue;
    			}

    			smp = mx->smp + ch->smp;

    			mix_channel(mx, cnt, mix_buf, mix_buf_pos, gap_size);
    		}

    		mix_buf_pos    += gap_size;
    		mx->count_down -= gap_size;
    	}

    convert:
    	//filter_dc(mx, mix_buf, length);

    	quantize(mix_buf, buffer, length * mx->output.channels, mx->output.format);

    	mpl__mem_free(mix_buf);

    	return 0;
    }

    static int
    mixer_command_get_num_active_channels(void *internal)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;
    	int ch, cnt;

    	cnt = 0;

    	for(ch = 0; ch < mx->ch_num; ch++)
    	{
    		if (mx->ch[ch].playing)
    		{
    			cnt++;
    		}
    	}

    	return cnt;
    }

    static int
    mixer_command_get_interface(void *internal, mpl__snd_mixer_t **mixer)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) internal;

    	*mixer = &mx->iface;

    	return 0;
    }

    ///////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////

    int
    mpl__mx_std_create(mpl__mixer_t **mixer)
    {
    	mpl__mx_std_t *mx;

    	if (mpl__mem_alloc(sizeof(mpl__mixer_t), (void**)mixer) <= MPL__ERR_GENERIC)
    	{
    		return MPL__ERR_NOMEM;
    	}

    	if (mpl__mem_alloc(sizeof(mpl__mx_std_t), (void**)&mx) <= MPL__ERR_GENERIC)
    	{
    		mpl__mem_free(*mixer);

    		return MPL__ERR_NOMEM;
    	}

    	if (mpl__mem_alloc(sizeof(mpl__mx_std_ch_t) * 2, (void**)&mx->ch) <= MPL__ERR_GENERIC)
    	{
    		mpl__mem_free(*mixer);
    		mpl__mem_free(mx);

    		return MPL__ERR_NOMEM;
    	}

    	if (mpl__mem_alloc(sizeof(mpl__mx_std_smp_t), (void**)&mx->smp) <= MPL__ERR_GENERIC)
    	{
    		mpl__mem_free(*mixer);
    		mpl__mem_free(mx);
    		mpl__mem_free(mx->ch);

    		return MPL__ERR_NOMEM;
    	}

    	(*mixer)->get_interface           = mixer_command_get_interface;
    	(*mixer)->get_num_active_channels = mixer_command_get_num_active_channels;
    	(*mixer)->get_options             = mixer_command_get_options;
    	(*mixer)->get_proc                = mixer_command_get_proc;
    	(*mixer)->mix                     = mixer_command_mix;
    	(*mixer)->set_options             = mixer_command_set_options;
    	(*mixer)->set_output_options      = mixer_command_set_output_options;
    	(*mixer)->set_vol                 = mixer_command_set_vol;

    	(*mixer)->internal_data = mx;

    	mx->iface.destroy_sample          = command_destroy_sample;
    	mx->iface.get_free_channel        = command_get_free_channel;
    	mx->iface.get_latency             = command_get_latency;
    	mx->iface.get_num_active_channels = command_get_num_active_channels;
    	mx->iface.get_num_channels        = command_get_num_channels;
    	mx->iface.get_option              = command_get_option;
    	mx->iface.get_output_options      = command_get_output_options;
    	mx->iface.get_proc                = command_get_proc;
    	mx->iface.get_vol                 = command_get_vol;
    	mx->iface.is_channel_active       = command_is_channel_active;
    	mx->iface.pause                   = command_pause;
    	mx->iface.play_channel            = command_play_channel;
    	mx->iface.reset                   = command_reset;
    	mx->iface.set_call_back           = command_set_call_back;
    	mx->iface.set_channel_freq        = command_set_channel_freq;
    	mx->iface.set_channel_pos         = command_set_channel_pos;
    	mx->iface.set_channel_vol         = command_set_channel_vol;
    	mx->iface.set_option              = command_set_option;
    	mx->iface.set_vol                 = command_set_vol;
    	mx->iface.stop                    = command_stop;
    	mx->iface.stop_channel            = command_stop_channel;
    	mx->iface.upload_sample           = command_upload_sample;

    	mx->iface.internal_data = mx;

    	mx->smp_num         = 1;
    	mx->smp->exists     = 0;

    	mx->ch_num          = 1;
    	mx->ch[0].playing   = 0;
    	mx->ch[1].playing   = 0;

    	mx->count_down_frac = 0;
    	mx->call_back.func  = 0;
    	mx->latency         = 0;
    	mx->mem_usage       = MPL__MX_MEM_LOW;
    	mx->output.channels = 2;
    	mx->output.format   = MPL__SND_DEV_FMT_16BIT;
    	mx->output.freq     = 44100;
    	mx->output.latency  = MPL__SND_DEV_LATENCY_HIGH;
    	mx->paused          = 0;
    	mx->qual            = MPL__MX_HQ;
    	mx->vol_global      = 1.0f;
    	mx->pan_lr_global   = 0.5f;
    	mx->pan_fb_global   = 0.5f;
    	mx->vol_local       = 1.0f;
    	mx->pan_lr_local    = 0.5f;
    	mx->pan_fb_local    = 0.5f;
    	mx->dc_spd[0]       = 0;
    	mx->dc_pos[0]       = 0;
    	mx->dc_spd[1]       = 0;
    	mx->dc_pos[1]       = 0;
    	mx->ramp            = 1.0f / (44100 * RAMPING);

    	return 0;
    }

    void
    mpl__mx_std_destroy(mpl__mixer_t *mixer)
    {
    	mpl__mx_std_t *mx = (mpl__mx_std_t*) mixer->internal_data;

    	mpl__mem_free(mx->ch);
    	mpl__mem_free(mx->smp);
    	mpl__mem_free(mx);
    	mpl__mem_free(mixer);
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/src/main.c] - (6,817 bytes)

    #include <windows.h>
    #include <malloc.h>
    #include <process.h>
    #include <mmsystem.h>
    #include <dsound.h>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #include <conio.h>

    #include <stdio.h>
    #include <vbf/vbf_std.h>
    #include <mpl/mx_std.h>
    #include <mpl/ml_xm.h>
    #include <mpl/sys/mem.h>

    #define PLAYFREQ 44100

    mpl__mixer_t *mixah;

    LPDIRECTSOUND8 ds8 = 0;
    WAVEFORMATEX format;
    DSBUFFERDESC desc;
    LPDIRECTSOUNDBUFFER8 buf = 0;
    int bufpos;

    void *tmpbuf;
    int tmpbufsize;
    int kill=0;
    int playing=0;

    double sine_pos = 0;

    void
    fillwf(WAVEFORMATEX *wf, int ch, int freq, int bits)
    {
    	wf->wFormatTag      = WAVE_FORMAT_PCM;
    	wf->nChannels       = ch;
    	wf->nSamplesPerSec  = freq;
    	wf->wBitsPerSample  = bits;
    	wf->nBlockAlign     = bits * ch >> 3;
    	wf->nAvgBytesPerSec = wf->nSamplesPerSec * wf->nBlockAlign;
    }

    int
    init()
    {
    	if (FAILED(DirectSoundCreate8(0, &ds8, 0)))
    	{
    		return -1;
    	}

    	if (FAILED(ds8->lpVtbl->SetCooperativeLevel(ds8, GetForegroundWindow(), DSSCL_NORMAL)))
    	{
    		return -1;
    	}

    	kill = 0;

    	return 0;
    }

    void
    shutitdown()
    {
    	if (playing)
    	{
    		kill = 1;

    		while(kill) Sleep(5);
    	}

    	if (buf)
    	{
    		IUnknown_Release(buf);
    		buf = 0;
    	}

    	if (ds8)
    	{
    		IUnknown_Release(ds8);
    		ds8 = 0;
    	}
    }

    int
    setprimarybufferformat(int ch, int freq, int bits)
    {
    	LPDIRECTSOUNDBUFFER primbuf;
    	WAVEFORMATEX format;
    	DSBUFFERDESC desc;

    	desc.dwBufferBytes = 0;
    	desc.lpwfxFormat   = 0;
    	desc.dwFlags       = DSBCAPS_PRIMARYBUFFER;
    	desc.dwSize        = sizeof(DSBUFFERDESC);
    	desc.dwReserved    = 0;

    	if (FAILED(ds8->lpVtbl->CreateSoundBuffer(ds8, &desc, &primbuf, 0)))
    	{
    		return -1;
    	}

    	fillwf(&format, ch, freq, bits);

    	if (FAILED(primbuf->lpVtbl->SetFormat(primbuf, &format)))
    	{
    		IUnknown_Release(primbuf);

    		return -1;
    	}

    	IUnknown_Release(primbuf);

    	return 0;
    }

    int
    calc_space_left()
    {
    	int readpos, writepos;

    	buf->lpVtbl->GetCurrentPosition(buf, &readpos, &writepos);

    	if (bufpos < readpos)
    	{
    		return readpos - bufpos;
    	}

    	return desc.dwBufferBytes - bufpos + readpos;
    }

    int
    write_data(void *data, mpl__mem_size_t size)
    {
    	int result, length1, length2;
    	void *address1, *address2;

    	result = buf->lpVtbl->Lock(buf, bufpos, size,
    							   &address1, &length1,
    							   &address2, &length2,
    							   0);

    	if (result == DSERR_BUFFERLOST)
    	{
    		buf->lpVtbl->Restore(buf);

    		result = buf->lpVtbl->Lock(buf, bufpos, size,
    								   &address1, &length1,
    								   &address2, &length2,
    								   0);
    	}

    	if (result != DS_OK)
    	{
    		return 0;
    	}

    	mpl__mem_copy(data, address1, length1);

    	if (length2)
    	{
    		mpl__mem_copy(((i8*)data) + length1, address2, length2);
    	}

    	buf->lpVtbl->Unlock(buf, address1, length1, address2, length2);

    	return 1;
    }

    int
    fillbuf()
    {
    	mpl__mixer_mix(mixah, tmpbuf, tmpbufsize);

    	return 0;
    }

    void __cdecl
    dsthread(void *param)
    {
    	fillbuf();

    	while(!kill)
    	{
    		if (calc_space_left() > tmpbufsize * format.nBlockAlign)
    		{
    			write_data(tmpbuf, tmpbufsize * format.nBlockAlign);

    			bufpos += tmpbufsize * format.nBlockAlign;
    			bufpos %= desc.dwBufferBytes;

    			fillbuf();
    		}

    		Sleep(5);
    	}

    	kill = 0;
    }

    int
    setparams(int ch, int freq, int bits)
    {
    	if (buf)
    	{
    		IUnknown_Release(buf);
    		buf = 0;
    	}

    	fillwf(&format, ch, freq, bits);

    	desc.dwBufferBytes = format.nBlockAlign * (int)(freq * 0.1);
    	desc.lpwfxFormat   = &format;
    	desc.dwFlags       = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
    	desc.dwSize        = sizeof(DSBUFFERDESC);
    	desc.dwReserved    = 0;

    	if (FAILED(ds8->lpVtbl->CreateSoundBuffer(ds8, &desc, (struct IDirectSoundBuffer**)&buf, 0)))
    	{
    		return -1;
    	}

    	tmpbufsize = (desc.dwBufferBytes / format.nBlockAlign) >> 2;

    	if (mpl__mem_alloc(format.nBlockAlign * tmpbufsize, &tmpbuf) <= MPL__ERR_GENERIC)
    	{
    		IUnknown_Release(buf);
    		buf = 0;
    		return -1;
    	}

    	SetThreadPriority((HANDLE)_beginthread(dsthread, 0, 0), THREAD_PRIORITY_TIME_CRITICAL);

    	return 0;
    }

    int
    play()
    {
    	if (buf->lpVtbl->Play(buf, 0, 0, DSBPLAY_LOOPING) != DS_OK)
    	{
    		return -1;
    	}

    	playing = 1;

    	return 0;
    }

    int
    clear()
    {
    	int result, length;
    	char *bufpnt;

    	result = buf->lpVtbl->Lock(buf, 0, desc.dwBufferBytes,
    							   &bufpnt, &length,
    							   0, 0,
    							   0);

    	if (result == DSERR_BUFFERLOST)
    	{
    		buf->lpVtbl->Restore(buf);

    		result = buf->lpVtbl->Lock(buf, 0, desc.dwBufferBytes,
    								   &bufpnt, &length,
    								   0, 0,
    								   0);
    	}

    	if (result != DS_OK)
    	{
    		return 0;
    	}

    	while(length--)
    	{
    		bufpnt[length] = 0;
    	}

    	buf->lpVtbl->Unlock(buf, bufpnt, desc.dwBufferBytes, 0, 0);

    	return 1;
    }

    void
    stop()
    {
    	buf->lpVtbl->Stop(buf);

    	playing = 0;
    }

    int
    cmd_cm(void *internal, mpl__snd_mixer_t **mixer, mpl__snd_mixer_opt_t opt)
    {
    	mpl__mixer_opt_t mopt;
    	mpl__mixer_t *mx;
    	mpl__snd_dev_output_t out;

    	mpl__mx_std_create(&mx);

    	mixah = mx;

    	mopt.ch_num = opt.ch_num;
    	mopt.mem_usage = 0;
    	mopt.qual = MPL__MX_HQ;
    	mopt.smp_num = opt.smp_num;

    	mpl__mixer_set_options(mx, &mopt);
    	mpl__mixer_set_vol(mx, 1.0f, 0.5f, 0.5f);

    	out.channels = 2;
    	out.format = MPL__SND_DEV_FMT_16BIT;
    	out.freq = PLAYFREQ;
    	out.latency = 0;

    	mpl__mixer_set_output_options(mx, &out, 100);

    	mpl__mixer_get_interface(mx, mixer);

    	return 0;
    }

    int
    cmd_dm(void *internal, mpl__snd_mixer_t *mixer)
    {
    	return 0;
    }

    int
    cmd_goo(void *internal, mpl__snd_dev_output_t *opt)
    {
    	opt->channels = 2;
    	opt->format = 2;
    	opt->freq = PLAYFREQ;
    	opt->latency = 0;

    	return 0;
    }

    i16 buffer[2 * 10 * PLAYFREQ];

    int
    main(int argc, char **argv)
    {

    	mpl__xm_t xm;
    	mpl__mp_t mp;
    	vbf_t file;
    	mpl__snd_dev_t dev;
    	FILE *rg;

    	mpl__mem_init();

    	if (argc != 2)
    	{
    		printf("syntax: %s filename.xm\n", argv[0]);
    		return 0;
    	}

    	dev.create_mixer = cmd_cm;
    	dev.destroy_mixer = cmd_dm;
    	dev.get_output_options = cmd_goo;

    	rg = fopen(argv[1], "rb");
    	if (!rg)
    	{
    		printf("file not found\n");
    		return 0;
    	}

    	vbf_std_open(&file, rg);
    	mpl__xm_load(&file, &xm);
    	vbf_close(&file);
    	fclose(rg);

    	if (mpl__mp_xm_construct(&xm, &mp, 0) < MPL__ERR_OK)
    	{
    		printf("error\n");
    		return 0;
    	}

    	if (mpl__mp_set_dev(&mp, &dev) < MPL__ERR_OK)
    	{
    		printf("couldn't set device\n");
    		return 0;
    	}

    	if (mpl__mp_set_vol(&mp, 0.6f) < MPL__ERR_OK)
    	{
    		printf("error\n");
    		return 0;
    	}

    	if (mpl__mp_play(&mp) < MPL__ERR_OK)
    	{
    		printf("error\n");
    		return 0;
    	}

    	mpl__mp_set_loop(&mp, 4);

    	init();
    	setparams(2, PLAYFREQ, 16);
    	clear();
    	play();

    	printf("playin'.....\n");

    	while(!kbhit()) Sleep(100);
    	stop();

    	return 0;
    }

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/sys_cfg.h] - (771 bytes)

    #ifndef sys_cfg_h_n423788423342
    #define sys_cfg_h_n423788423342

    typedef __int64              i64;
    typedef unsigned __int64     u64;
    //typedef long long            i64;
    //typedef unsigned long long   u64;
    typedef int                  i32;
    typedef unsigned int         u32;
    typedef short                i16;
    typedef unsigned short       u16;
    typedef char                 i8;
    typedef unsigned char        u8;

    typedef float                float32;
    typedef double               float64;
    //typedef long double          float80;

    typedef short                wide_char;

    typedef void(*void_func_t)(void);

    #define SYS_SMALL_ENDIAN     1
    //#define SYS_BIG_ENDIAN       1

    //#define SYS_MINI_VERSION     1

    #define inline_function __inline

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/vbf/vbf_mem.h] - (184 bytes)

    #ifndef vbf_mem_h_n4237878942373243422348
    #define vbf_mem_h_n4237878942373243422348

    #include <vbf/vbf.h>

    int vbf_mem_open(vbf_t *vbf, void *buffer, vbf_size_t size);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/vbf/vbf_std.h] - (183 bytes)

    #ifndef vbf_std_h_n478278423789423789342
    #define vbf_std_h_n478278423789423789342

    #include <vbf/vbf.h>
    #include <stdio.h>

    int vbf_std_open(vbf_t *vbf, FILE *file);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/vbf/vbf_util.h] - (1,654 bytes)

    #ifndef vbf_util_h_n4782378243893
    #define  vbf_util_h_n4782378243893

    #include <vbf/vbf.h>
    #include <sys_cfg.h>

    #define VBF_BIG_ENDIAN       0
    #define VBF_SMALL_ENDIAN     1

    int vbf_read_u64(vbf_t *vbf, int endianess, u64 *val);
    int vbf_read_i64(vbf_t *vbf, int endianess, i64 *val);
    int vbf_read_u32(vbf_t *vbf, int endianess, u32 *val);
    int vbf_read_i32(vbf_t *vbf, int endianess, i32 *val);
    int vbf_read_u16(vbf_t *vbf, int endianess, u16 *val);
    int vbf_read_i16(vbf_t *vbf, int endianess, i16 *val);
    int vbf_read_u8(vbf_t *vbf, int endianess, u8 *val);
    int vbf_read_i8(vbf_t *vbf, int endianess, i8 *val);
    int vbf_read_float32(vbf_t *vbf, int endianess, float32 *val);
    int vbf_read_float64(vbf_t *vbf, int endianess, float64 *val);

    int vbf_read_array_u64(vbf_t *vbf, int endianess, int num, u64 *val);
    int vbf_read_array_i64(vbf_t *vbf, int endianess, int num, i64 *val);
    int vbf_read_array_u32(vbf_t *vbf, int endianess, int num, u32 *val);
    int vbf_read_array_i32(vbf_t *vbf, int endianess, int num, i32 *val);
    int vbf_read_array_u16(vbf_t *vbf, int endianess, int num, u16 *val);
    int vbf_read_array_i16(vbf_t *vbf, int endianess, int num, i16 *val);
    int vbf_read_array_u8(vbf_t *vbf, int endianess, int num, u8 *val);
    int vbf_read_array_i8(vbf_t *vbf, int endianess, int num, i8 *val);
    int vbf_read_array_float32(vbf_t *vbf, int endianess, int num, float32 *val);
    int vbf_read_array_float64(vbf_t *vbf, int endianess, int num, float64 *val);

    int vbf_read_line_char(vbf_t *vbf, char *buf, int max, int *read);
    int vbf_read_line_wide_char(vbf_t *vbf, int endianess, wide_char *buf, int max, int *read);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/vbf/vbf.h] - (1,632 bytes)

    #ifndef vbf_h_n423789784923789423
    #define vbf_h_n423789784923789423

    #include <sys_cfg.h>

    #define VBF_ATTR_OPEN     1
    #define VBF_ATTR_READ     2
    #define VBF_ATTR_WRITE    4
    #define VBF_ATTR_APPEND   8
    #define VBF_ATTR_SEEK     16
    #define VBF_ATTR_LENGTH   32

    #define VBF_ERR_GENERIC   -1
    #define VBF_ERR_BAD_POS   -2
    #define VBF_ERR_NOT_OPEN  -3
    #define VBF_ERR_NO_LENGTH -4
    #define VBF_ERR_NO_SEEK   -5
    #define VBF_ERR_NO_READ   -6
    #define VBF_ERR_NO_WRITE  -7

    typedef long int vbf_size_t;

    typedef struct vbf_s {
    	int        mode;
    	vbf_size_t pos, length;
    	void       *data;

    	int (*raw_read)(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    	int (*raw_write)(struct vbf_s *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    	int (*raw_ioctl)(struct vbf_s *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    	int (*raw_seek_rel)(struct vbf_s *vbf, vbf_size_t new_pos);
    	int (*raw_close)(struct vbf_s *vbf);
    } vbf_t;

    int vbf_create(vbf_t *vbf);
    int vbf_destroy(vbf_t *vbf);

    int vbf_seek_beg(vbf_t *vbf, vbf_size_t pos);
    int vbf_seek_cur(vbf_t *vbf, vbf_size_t pos);
    int vbf_seek_end(vbf_t *vbf, vbf_size_t pos);
    int vbf_tell(vbf_t *vbf, vbf_size_t *pos);
    int vbf_size(vbf_t *vbf, vbf_size_t *size);
    int vbf_mode(vbf_t *vbf, int *mode);
    int vbf_read(vbf_t *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    int vbf_write(vbf_t *vbf, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    int vbf_ioctl(vbf_t *vbf, int command, void *buffer, vbf_size_t size, vbf_size_t *out_size);
    int vbf_close(vbf_t *vbf);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/biquad.h] - (867 bytes)

    #ifndef biquad_h_n43287238497789234
    #define biquad_h_n43287238497789234

    #include <sys_cfg.h>

    /*
    usage:

    y[n] = a0 * x[n] + a1 * x[n-1] + a2 * x[n-2] +
                       b1 * y[n-1] + b2 * y[n-2]
    */

    typedef struct {
    	double a0, a1, a2,
    		       b1, b2;
    } mpl__biquad_coeff_t;

    void mpl__fil_lp(mpl__biquad_coeff_t *fil, float omega, float bandwidth);
    void mpl__fil_bp(mpl__biquad_coeff_t *fil, float omega, float bandwidth);
    void mpl__fil_hp(mpl__biquad_coeff_t *fil, float omega, float bandwidth);
    void mpl__fil_no(mpl__biquad_coeff_t *fil, float omega, float bandwidth);
    void mpl__fil_peq(mpl__biquad_coeff_t *fil, float omega, float bandwidth, float dbgain);
    void mpl__fil_ls(mpl__biquad_coeff_t *fil, float omega, float dbgain, float slope);
    void mpl__fil_hs(mpl__biquad_coeff_t *fil, float omega, float dbgain, float slope);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/sd_std.h] - (445 bytes)

    #ifndef sd_std_h_n34782823478789234
    #define sd_std_h_n34782823478789234

    #include <mpl/mx.h>

    typedef struct mpl__sd_std_s {
    	int  (*mx_create)(mpl__mixer_t **mixer);
    	void (*mx_destroy)(mpl__mixer_t *mixer);

    	mpl__mixer_t *mx[4];
    } mpl__sd_std_t;

    int mpl__sd_std_create(mpl__snd_dev_t **sd, int  (*mx_create)(mpl__mixer_t **mixer), void (*mx_destroy)(mpl__mixer_t *mixer));
    void mpl__sd_std_destroy(mpl__snd_dev_t *sd);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/error.h] - (469 bytes)

    #ifndef error_h_n473784923
    #define error_h_n473784923

    // to be done

    #define MPL__ERR_OK                                0
    #define MPL__ERR_GENERIC                          -1
    #define MPL__ERR_BAD_PARAM                        -2

    #define MPL__ERR_NOMEM                            -3

    #define MPL__ERR_MSG_BOX_FULL                     -4
    #define MPL__ERR_MSG_BOX_EMPTY                    -5

    #define MPL__ERR_EOS                              -6

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/ml.h] - (1,176 bytes)

    #ifndef ml_h_n31783892389
    #define ml_h_n31783892389

    #include <mpl/sys/msg_box.h>
    #include <vbf/vbf.h>
    #include <mpl/mp.h>
    #include <mpl/error.h>

    typedef void mpl__md_t;

    typedef struct mpl__ml_s {
    	int (*load)(void *internal, vbf_t *file, mpl__md_t **md);
    	int (*destroy)(void *internal, mpl__md_t *md);

    	int (*create_mp)(void *internal, mpl__md_t *md, mpl__msg_box_t *mb, mpl__mp_t **mp);
    	int (*destroy_mp)(void *internal, mpl__mp_t **mp);

    	int (*set_option)(void *internal, char *option, char *value);
    	int (*get_option)(void *internal, char *option, char **value);
    	int (*get_proc)(void *internal, char *name, void_func_t *proc);

    	void *internal_data;
    } mpl__ml_t;

    int mpl__ml_load(mpl__ml_t *ml, vbf_t *file, mpl__md_t **md);
    int mpl__ml_destroy(mpl__ml_t *ml, mpl__md_t *md);
    int mpl__ml_create_mp(mpl__ml_t *ml, mpl__md_t *md, mpl__msg_box_t *mb, mpl__mp_t **mp);
    int mpl__ml_destroy_mp(mpl__ml_t *ml, mpl__mp_t **mp);
    int mpl__ml_set_option(mpl__ml_t *ml, char *option, char *value);
    int mpl__ml_get_option(mpl__ml_t *ml, char *option, char **value);
    int mpl__ml_get_proc(mpl__ml_t *ml, char *name, void_func_t *proc);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/mp.h] - (1,564 bytes)

    #ifndef mp_h_n432789237
    #define mp_h_n432789237

    #include <mpl/snddev.h>

    #define MPL__MP_LOOP_NONE      0
    #define MPL__MP_LOOP_FOREVER   -1

    #define MPL__MP_MSG_RESTART    0
    #define MPL__MP_MSG_END        1

    typedef struct mpl__mp_s {
    	int (*set_dev)(void *internal_data, mpl__snd_dev_t *dev);

    	int (*reset)(void *internal_data);

    	int (*play)(void *internal_data);
    	int (*stop)(void *internal_data);
    	int (*set_loop)(void *internal_data, int loop);

    	// typically: 0xXXXYYY (XXX = pattern, YYY = row)
    	int (*set_pos)(void *internal_data, int pos);
    	int (*get_pos)(void *internal_data);

    	int (*set_vol)(void *internal_data, float32 vol);
    	int (*get_vol)(void *internal_data, float32 *vol);

    	int (*set_option)(void *internal, char *option, char *value);
    	int (*get_option)(void *internal, char *option, char **value);
    	int (*get_proc)(void *internal, char *name, void_func_t *proc);

    	void *internal_data;
    } mpl__mp_t;

    int mpl__mp_set_dev(mpl__mp_t *mp, mpl__snd_dev_t *dev);
    int mpl__mp_reset(mpl__mp_t *mp);
    int mpl__mp_play(mpl__mp_t *mp);
    int mpl__mp_stop(mpl__mp_t *mp);
    int mpl__mp_set_loop(mpl__mp_t *mp, int loop);
    int mpl__mp_set_pos(mpl__mp_t *mp, int pos);
    int mpl__mp_get_pos(mpl__mp_t *mp);
    int mpl__mp_set_vol(mpl__mp_t *mp, float32 vol);
    int mpl__mp_get_vol(mpl__mp_t *mp, float32 *vol);
    int mpl__mp_set_option(mpl__mp_t *mp, char *option, char *value);
    int mpl__mp_get_option(mpl__mp_t *mp, char *option, char **value);
    int mpl__mp_get_proc(mpl__mp_t *mp, char *name, void_func_t *proc);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/mx.h] - (1,585 bytes)

    #ifndef mx_h_n7238478432789423
    #define mx_h_n7238478432789423

    #include <mpl/snddev.h>

    #define MPL__MX_MEM_AGGRESSIVE   0
    #define MPL__MX_MEM_LOW          1

    #define MPL__MX_HQ               0  // high quality
    #define MPL__MX_LQ               1  // low quality

    typedef struct mpl__mixer_opt_s {
    	int ch_num, smp_num, mem_usage, qual;
    } mpl__mixer_opt_t;

    typedef struct mpl__mixer_s {
    	int (*set_output_options)(void *internal, mpl__snd_dev_output_t *opt, int latency);
    	int (*set_options)(void *internal, mpl__mixer_opt_t *opt);
    	int (*get_options)(void *internal, mpl__mixer_opt_t *opt);
    	int (*get_proc)(void *internal, char *name, void_func_t *func);
    	int (*get_interface)(void *internal, mpl__snd_mixer_t **mixer);

    	int (*set_vol)(void *internal, float32 vol, float32 pan_lr, float32 pan_fb);

    	int (*mix)(void *internal, void *buffer, int length);

    	int (*get_num_active_channels)(void *internal);

    	void *internal_data;
    } mpl__mixer_t;

    int mpl__mixer_set_output_options(mpl__mixer_t *mx, mpl__snd_dev_output_t *opt, int latency);
    int mpl__mixer_set_options(mpl__mixer_t *mx, mpl__mixer_opt_t *opt);
    int mpl__mixer_get_options(mpl__mixer_t *mx, mpl__mixer_opt_t *opt);
    int mpl__mixer_get_proc(mpl__mixer_t *mx, char *name, void_func_t *func);
    int mpl__mixer_get_interface(mpl__mixer_t *mx, mpl__snd_mixer_t **mixer);
    int mpl__mixer_set_vol(mpl__mixer_t *mx, float32 vol, float32 pan_lr, float32 pan_fb);
    int mpl__mixer_mix(mpl__mixer_t *mx, void *buffer, int length);
    int mpl__mixer_get_num_active_channels(mpl__mixer_t *mx);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/snddev.h] - (9,913 bytes)

    #ifndef snddev_h_n478237842378
    #define snddev_h_n478237842378

    // notes:
    //
    // data is always signed (any need for unsigned data?!?)

    #include <sys_cfg.h>
    #include <mpl/error.h>

    #define MPL__SND_DEV_FMT_NONLOOPING    0
    #define MPL__SND_DEV_FMT_LOOPING       1
    #define MPL__SND_DEV_FMT_BIDILOOPING   2

    #define MPL__SND_DEV_FMT_8BIT          1
    #define MPL__SND_DEV_FMT_16BIT         2
    #define MPL__SND_DEV_FMT_24BIT         3
    #define MPL__SND_DEV_FMT_32BIT         4
    #define MPL__SND_DEV_FMT_FLOAT_32BIT   5

    #define MPL__SND_DEV_LATENCY_HIGH      0
    #define MPL__SND_DEV_LATENCY_LOW       1

    #define MPL__SND_DEV_DIR_FORWARDS      0
    #define MPL__SND_DEV_DIR_BACKWARDS     1

    typedef struct mpl__snd_dev_output_s {
    	int format;
    	int channels;
    	float32 freq;
    	int latency;
    } mpl__snd_dev_output_t;

    typedef void(*mpl__snd_call_back_func_t)(void *data, int param);

    typedef struct mpl__snd_mixer_call_back_s {
    	mpl__snd_call_back_func_t	func;
    	void						*data;
    	int							param;
    	float64						period;
    } mpl__snd_call_back_t;

    typedef struct mpl__snd_dev_smp_s {
    	int			format;
    	int			channels;
    	int			loopmode;
    	int			loop;
    	int			length;
    	float32		vol;
    	float32		pan_lr;
    	float32		pan_fb;
    	float32		freq;
    	void		*data;
    } mpl__snd_mixer_smp_t;

    typedef struct mpl__snd_mixer_s {
    	int (*reset)(void *internal);  // stops playing, toasts samples
    	int (*pause)(void *internal);  // 1 -> paused | 0 -> unpaused ; doesn't run callback
    	int (*stop)(void *internal);

    	int (*upload_sample)(void *internal, mpl__snd_mixer_smp_t sample);
    	int (*destroy_sample)(void *internal, int handle);

    	int (*set_vol)(void *internal, float32 vol, float32 pan_lr, float32 pan_fb);
    	int (*get_vol)(void *internal, float32 *vol, float32 *pan_lr, float32 *pan_fb);

    	int (*get_output_options)(void *internal, mpl__snd_dev_output_t *opt);
    	int (*get_latency)(void *internal);   // ms

    	int (*get_num_channels)(void *internal);
    	int (*get_num_active_channels)(void *internal);
    	int (*get_free_channel)(void *internal);
    	int (*is_channel_active)(void *internal, int ch);

    	int (*set_channel_vol)(void *internal, int ch, float32 vol, float32 pan_lr, float32 pan_fb);
    	int (*set_channel_freq)(void *internal, int ch, float32 freq);
    	int (*set_channel_pos)(void *internal, int ch, float64 pos, int dir);
    	int (*play_channel)(void *internal, int ch, int handle, float32 freq, float32 vol, float32 pan_lr, float32 pan_fb, float64 pos, int dir);
    	int (*stop_channel)(void *internal, int ch);

    	/*
    		getoption(...)

    		"ID"
    		"VERSION"
    		"AUTHOR"
    		"EXTENSIONS" -> e.g. "EXT_MMX EXT_EQ EXT_REVERB"....
    	*/
    	int (*set_option)(void *internal, char *option, char *value);
    	int (*get_option)(void *internal, char *option, char **value);
    	int (*get_proc)(void *internal, char *name, void_func_t *proc);

    	int (*set_call_back)(void *internal, mpl__snd_call_back_t call_back);

    	void *internal_data;
    } mpl__snd_mixer_t;

    typedef struct mpl__snd_mixer_opt_s {
    	int			ch_num;   // min number of channels
    	int			smp_num;  // min number of samples
    	int			latency;
    } mpl__snd_mixer_opt_t;

    typedef struct mpl__snd_stream_format_s {
    	int			format;
    	int			channels;
    	float32		freq;
    } mpl__snd_stream_format_t;

    typedef struct mpl__snd_stream_opt_s {
    	mpl__snd_stream_format_t	format;
    	int							latency;
    } mpl__snd_stream_opt_t;

    typedef struct mpl__snd_stream_s {
    	int (*set_vol)(void *internal, float32 vol, float32 pan_lr, float32 pan_fb);
    	int (*get_vol)(void *internal, float32 *vol, float32 *pan_lr, float32 *pan_fb);

    	int (*get_output_options)(void *internal, mpl__snd_dev_output_t *opt);
    	int (*set_input_format)(void *internal, mpl__snd_stream_format_t *opt);
    	int (*get_input_format)(void *internal, mpl__snd_stream_format_t *opt);
    	int (*get_latency)(void *internal);   // ms
    	int (*get_buffer_size)(void *internal); // ms

    	int (*write)(void *internal, void *data, int length);

    	int (*set_option)(void *internal, char *option, char *value);
    	int (*get_option)(void *internal, char *option, char **value);
    	int (*get_proc)(void *internal, char *name, void_func_t *proc);

    	int (*set_call_back)(void *internal, mpl__snd_call_back_t call_back);

    	void *internal_data;
    } mpl__snd_stream_t;

    typedef struct mpl__snd_dev_s {
    	int (*set_vol)(void *internal, float32 vol, float32 pan_lr, float32 pan_fb);
    	int (*get_vol)(void *internal, float32 *vol, float32 *pan_lr, float32 *pan_fb);

    	int (*set_output_options)(void *internal, mpl__snd_dev_output_t opt);
    	int (*get_output_options)(void *internal, mpl__snd_dev_output_t *opt);

    	int (*set_latency)(void *internal, int latency);
    	int (*get_latency)(void *internal);   // ms

    	int (*set_option)(void *internal, char *option, char *value);
    	int (*get_option)(void *internal, char *option, char **value);
    	int (*get_proc)(void *internal, char *name, void_func_t *proc);

    	int (*create_mixer)(void *internal, mpl__snd_mixer_t **mixer, mpl__snd_mixer_opt_t opt);
    	int (*destroy_mixer)(void *internal, mpl__snd_mixer_t *mixer);

    	int (*create_stream)(void *internal, mpl__snd_stream_t **stream, mpl__snd_stream_opt_t opt);
    	int (*destroy_stream)(void *internal, mpl__snd_stream_t *stream);

    	void *internal_data;
    } mpl__snd_dev_t;

    // dev

    int mpl__snd_dev_set_vol(mpl__snd_dev_t *dev, float32 vol, float32 pan_lr, float32 pan_fb);
    int mpl__snd_dev_get_vol(mpl__snd_dev_t *dev, float32 *vol, float32 *pan_lr, float32 *pan_fb);
    int mpl__snd_dev_set_output_options(mpl__snd_dev_t *dev, mpl__snd_dev_output_t opt);
    int mpl__snd_dev_get_output_options(mpl__snd_dev_t *dev, mpl__snd_dev_output_t *opt);
    int mpl__snd_dev_set_latency(mpl__snd_dev_t *dev, int latency);
    int mpl__snd_dev_get_latency(mpl__snd_dev_t *dev);
    int mpl__snd_dev_set_option(mpl__snd_dev_t *dev, char *option, char *value);
    int mpl__snd_dev_get_option(mpl__snd_dev_t *dev, char *option, char **value);
    int mpl__snd_dev_get_proc(mpl__snd_dev_t *dev, char *name, void_func_t *proc);
    int mpl__snd_dev_create_mixer(mpl__snd_dev_t *dev, mpl__snd_mixer_t **mixer, mpl__snd_mixer_opt_t opt);
    int mpl__snd_dev_destroy_mixer(mpl__snd_dev_t *dev, mpl__snd_mixer_t *mixer);
    int mpl__snd_dev_create_stream(mpl__snd_dev_t *dev, mpl__snd_stream_t **stream, mpl__snd_stream_opt_t opt);
    int mpl__snd_dev_destroy_stream(mpl__snd_dev_t *dev, mpl__snd_stream_t *stream);

    // mixer

    int mpl__snd_mixer_reset(mpl__snd_mixer_t *mixer);  // stops playing, toasts samples
    int mpl__snd_mixer_pause(mpl__snd_mixer_t *mixer);  // 1 -> paused | 0 -> unpaused ; doesn't run callback
    int mpl__snd_mixer_stop(mpl__snd_mixer_t *mixer);
    int mpl__snd_mixer_upload_sample(mpl__snd_mixer_t *mixer, mpl__snd_mixer_smp_t sample);
    int mpl__snd_mixer_destroy_sample(mpl__snd_mixer_t *mixer, int handle);
    int mpl__snd_mixer_set_vol(mpl__snd_mixer_t *mixer, float32 vol, float32 pan_lr, float32 pan_fb);
    int mpl__snd_mixer_get_vol(mpl__snd_mixer_t *mixer, float32 *vol, float32 *pan_lr, float32 *pan_fb);
    int mpl__snd_mixer_get_output_options(mpl__snd_mixer_t *mixer, mpl__snd_dev_output_t *opt);
    int mpl__snd_mixer_get_latency(mpl__snd_mixer_t *mixer);   // ms
    int mpl__snd_mixer_get_num_channels(mpl__snd_mixer_t *mixer);
    int mpl__snd_mixer_get_num_active_channels(mpl__snd_mixer_t *mixer);
    int mpl__snd_mixer_get_free_channel(mpl__snd_mixer_t *mixer);
    int mpl__snd_mixer_is_channel_active(mpl__snd_mixer_t *mixer, int ch);
    int mpl__snd_mixer_set_channel_vol(mpl__snd_mixer_t *mixer, int ch, float32 vol, float32 pan_lr, float32 pan_fb);
    int mpl__snd_mixer_set_channel_freq(mpl__snd_mixer_t *mixer, int ch, float32 freq);
    int mpl__snd_mixer_set_channel_pos(mpl__snd_mixer_t *mixer, int ch, float64 pos, int dir);
    int mpl__snd_mixer_play_channel(mpl__snd_mixer_t *mixer, int ch, int handle, float32 freq, float32 vol, float32 pan_lr, float32 pan_fb, float64 pos, int dir);
    int mpl__snd_mixer_stop_channel(mpl__snd_mixer_t *mixer, int ch);
    int mpl__snd_mixer_set_option(mpl__snd_mixer_t *mixer, char *option, char *value);
    int mpl__snd_mixer_get_option(mpl__snd_mixer_t *mixer, char *option, char **value);
    int mpl__snd_mixer_get_proc(mpl__snd_mixer_t *mixer, char *name, void_func_t *proc);
    int mpl__snd_mixer_set_call_back(mpl__snd_mixer_t *mixer, mpl__snd_call_back_t call_back);

    // stream

    int mpl__snd_stream_set_vol(mpl__snd_stream_t *stream, float32 vol, float32 pan_lr, float32 pan_fb);
    int mpl__snd_stream_get_vol(mpl__snd_stream_t *stream, float32 *vol, float32 *pan_lr, float32 *pan_fb);
    int mpl__snd_stream_get_output_options(mpl__snd_stream_t *stream, mpl__snd_dev_output_t *opt);
    int mpl__snd_stream_set_input_format(mpl__snd_stream_t *stream, mpl__snd_stream_format_t *opt);
    int mpl__snd_stream_get_input_format(mpl__snd_stream_t *stream, mpl__snd_stream_format_t *opt);
    int mpl__snd_stream_get_latency(mpl__snd_stream_t *stream);   // ms
    int mpl__snd_stream_get_buffer_size(mpl__snd_stream_t *stream); // ms
    int mpl__snd_stream_set_option(mpl__snd_stream_t *stream, char *option, char *value);
    int mpl__snd_stream_get_option(mpl__snd_stream_t *stream, char *option, char **value);
    int mpl__snd_stream_get_proc(mpl__snd_stream_t *stream, char *name, void_func_t *proc);
    int mpl__snd_stream_write(mpl__snd_stream_t *stream, void *data, int length);
    int mpl__snd_stream_set_call_back(mpl__snd_stream_t *stream, mpl__snd_call_back_t call_back);

    //////////////////////////////////////////////////////////////
    // extensions

    #define MPL__EXT_SND_MIXER_SUSTAIN_LOOP      "EXT_SUSTAIN_LOOP"
    #define MPL__FUNC_SND_MIXER_SET_SUSTAIN_LOOP "mpl__snd_mixer_set_sustain_loop"
    #define MPL__FUNC_SND_MIXER_END_SUSTAIN      "mpl__snd_mixer_end_sustain"

    typedef int (*mpl__snd_mixer_set_sustain_loop_t)(mpl__snd_mixer_t *sndmx, int handle, int begin, int end, int mode);
    typedef int (*mpl__snd_mixer_end_sustain_t)(mpl__snd_mixer_t *sndmx, int ch);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/string.h] - (283 bytes)

    #ifndef string_h_n42378789234
    #define string_h_n42378789234

    #include <sys_cfg.h>

    #define MPL__STRING_EQUAL     1
    #define MPL__STRING_UNEQUAL   0

    int mpl__string_cmp_char(char *str1, char *str2);
    int mpl__string_cmp_wide_char(wide_char *str1, wide_char *str2);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/mp_xm.h] - (6,534 bytes)

    #ifndef mp_xm_h_n42378789234789342
    #define mp_xm_h_n42378789234789342

    #include <vbf/vbf_util.h>
    #include <mpl/sys/msg_box.h>
    #include <mpl/mp.h>

    #define MPL__XM_FREQ_TABLE_LINEAR             1

    #define MPL__XM_SMP_LOOP_BITS                 0x03

    #define MPL__XM_SMP_NO_LOOP                   0
    #define MPL__XM_SMP_LOOP                      1
    #define MPL__XM_SMP_BIDI_LOOP                 2

    #define MPL__XM_SMP_16BIT                     16

    // vol/pan envelope
    #define MPL__XM_ENV_ON                        1
    #define MPL__XM_ENV_SUSTAIN                   2
    #define MPL__XM_ENV_LOOP                      4

    #define MPL__XM_NO_NOTE                       98
    #define MPL__XM_KEY_OFF                       97

    #define MPL__XM_EFF_ARPEGGIO                  0x00
    #define MPL__XM_EFF_PORTA_UP                  0x01
    #define MPL__XM_EFF_PORTA_DOWN                0x02
    #define MPL__XM_EFF_PORTA                     0x03
    #define MPL__XM_EFF_VIB                       0x04
    #define MPL__XM_EFF_PORTA_VOL_SLIDE           0x05
    #define MPL__XM_EFF_VIB_VOL_SLIDE             0x06
    #define MPL__XM_EFF_TREMOLO                   0x07
    #define MPL__XM_EFF_PAN                       0x08
    #define MPL__XM_EFF_SMP_OFFSET                0x09
    #define MPL__XM_EFF_VOL_SLIDE                 0x0A
    #define MPL__XM_EFF_POS_JUMP                  0x0B
    #define MPL__XM_EFF_VOL                       0x0C
    #define MPL__XM_EFF_PAT_BREAK                 0x0D
    #define MPL__XM_EFF_MOD_EXT                   0x0E
    #define MPL__XM_EFF_SPEED                     0x0F
    #define MPL__XM_EFF_GLOB_VOL                  0x10
    #define MPL__XM_EFF_GLOB_VOL_SLIDE            0x11
    #define MPL__XM_EFF_KEY_OFF                   0x14
    #define MPL__XM_EFF_ENV_POS                   0x15
    #define MPL__XM_EFF_PAN_SLIDE                 0x19
    #define MPL__XM_EFF_RETRIG_VOL_SLIDE          0x1B
    #define MPL__XM_EFF_TREMOR                    0x1D
    #define MPL__XM_EFF_EXTRA_FINE_PORTA          0x21

    // Exx effects
    #define MPL__XM_EXT_EFF_FINE_PORTA_UP         0x10
    #define MPL__XM_EXT_EFF_FINE_PORTA_DOWN       0x20
    #define MPL__XM_EXT_EFF_GLISSANDO             0x30
    #define MPL__XM_EXT_EFF_VIB_WAVE              0x40
    #define MPL__XM_EXT_EFF_FINE_TUNE             0x50
    #define MPL__XM_EXT_EFF_PAT_LOOP              0x60
    #define MPL__XM_EXT_EFF_TREMOLO_WAVE          0x70
    #define MPL__XM_EXT_EFF_PAN                   0x80
    #define MPL__XM_EXT_EFF_RETRIG                0x90
    #define MPL__XM_EXT_EFF_FINE_VOL_SLIDE_UP     0xA0
    #define MPL__XM_EXT_EFF_FINE_VOL_SLIDE_DOWN   0xB0
    #define MPL__XM_EXT_EFF_NOTE_CUT              0xC0
    #define MPL__XM_EXT_EFF_NOTE_DELAY            0xD0
    #define MPL__XM_EXT_EFF_PAT_DELAY             0xE0

    #define MPL__XM_VOL_EFF_VOL_SLIDE_DOWN        0x60
    #define MPL__XM_VOL_EFF_VOL_SLIDE_UP          0x70
    #define MPL__XM_VOL_EFF_FINE_VOL_SLIDE_DOWN   0x80
    #define MPL__XM_VOL_EFF_FINE_VOL_SLIDE_UP     0x90
    #define MPL__XM_VOL_EFF_VIB_SPEED             0xA0
    #define MPL__XM_VOL_EFF_VIB                   0xB0
    #define MPL__XM_VOL_EFF_PAN                   0xC0
    #define MPL__XM_VOL_EFF_PAN_SLIDE_LEFT        0xD0
    #define MPL__XM_VOL_EFF_PAN_SLIDE_RIGHT       0xE0
    #define MPL__XM_VOL_EFF_PORTA                 0xF0

    #define MPL__XM_CTRL_VOL                      1
    #define MPL__XM_CTRL_PER                      2
    #define MPL__XM_CTRL_START                    4
    #define MPL__XM_CTRL_STOP                     8

    #define MPL__XM_PL_CTRL_BPM                   1
    #define MPL__XM_PL_CTRL_VOL                   2

    typedef struct {
    	int				index;

    	char			name[23];

    	int				loop_begin;
    	int				loop_end;

    	int				vol;
    	int				pan;

    	int				rel_note;
    	int				finetune;

    	int				length;
    	int				format;
    	void*			data;
    } mpl__xm_sample_t;

    typedef struct {
    	int x, y;
    } mpl__xm_point_t;

    typedef struct {
    	char			name[23];

    	int				note2smp[96];

    	mpl__xm_point_t vol_env[12];
    	int				vol_num;
    	int				vol_sus;
    	int				vol_loop_beg;
    	int				vol_loop_end;
    	int				vol_type;

    	int             vol_fade_out;

    	mpl__xm_point_t	pan_env[12];
    	int				pan_num;
    	int				pan_sus;
    	int				pan_loop_beg;
    	int				pan_loop_end;
    	int				pan_type;

    	int				vib_type;
    	int				vib_sweep;
    	int				vib_depth;
    	int				vib_rate;

    	int				smp_num;
    	mpl__xm_sample_t *smp;
    } mpl__xm_inst_t;

    typedef struct {
    	u8				key;
    	u8				inst;
    	u8				volume;
    	u8				effect;
    	u8				param;
    } mpl__xm_cell_t;

    typedef struct {
    	char			title[21];
    	char			tracker[21];

    	int				restart_pos;
    	int				length;
    	int				order[256];

    	int				inst_num;
    	mpl__xm_inst_t*		inst;
    	int				smp_index_num;

    	int				pat_num;
    	mpl__xm_cell_t*		pat[256];
    	int				pat_length[256];

    	int				ch_num;
    	int				bpm, speed;
    	int				freq_table;
    } mpl__xm_t;

    typedef struct {
    	int				active;
    	int				ctrl;
    	int				key;
    	int				real_key;
    	int				key_off;
    	int				eff;

    	int				inst;
    	mpl__xm_inst_t	*p_inst;
    	mpl__xm_sample_t *p_smp;
    //	double			sample_pos;
    	int				smp_offset;

    	int				vol;
    	int				vol_delta;
    	int				env_vol;
    	int				env_vol_tick;
    	int				fade_out_vol;

    	int				pan;
    	int				pan_delta;
    	int				env_pan;
    	int				env_pan_tick;

    	int				per;
    	int				per_delta;
    	int				dst_per;

    	int				porta_period;
    	int				porta_speed;

    	int				vib_speed;
    	int				vib_depth;
    	int				vib_pos;

    	int				inst_vib_sweep_pos;
    	int				inst_vib_pos;

    	int				tremolo_speed;
    	int				tremolo_depth;
    	int				tremolo_pos;

    	int				vol_slide;
    	int				fvol_slide_up;
    	int				fvol_slide_down;
    	int				vib_vol_slide;
    	int				porta_vol_slide;
    	int				retrig_vol_slide;
    	int				pan_slide;

    	int				loop_row;
    	int				loop_num;

    	int				porta_up;
    	int				porta_down;
    	int				fporta_up;
    	int				fporta_down;
    	int				efporta_up;
    	int				efporta_down;

    	int				tremor_pos;
    	int				tremor_spd;

    	int				wave_control;
    } mpl__mp_xm_chan_t;

    typedef struct {
    	mpl__xm_t		*xm;

    	int				pat_cur;
    	int				pat_next;
    	int				row_cur;
    	int				row_next;

    	int				bpm;
    	int				speed;
    	int				tick_cur;
    	int				delay;
    	int				ctrl;
    	int				paused;

    	mpl__mp_xm_chan_t ch[64];

    	int				smp_handle[300];
    	int             smp_fine_tune[300];

    	float32			vol;
    	int				glob_vol, glob_vol_slide;

    	int				loop;

    	mpl__snd_dev_t	*dev;
    	mpl__snd_mixer_t *mixer;
    	mpl__msg_box_t	*mb;
    } mpl__mp_xm_t;

    int mpl__mp_xm_construct(mpl__xm_t *xm, mpl__mp_t *mp, mpl__msg_box_t *mb);
    int mpl__mp_xm_destruct(mpl__mp_t *mp);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/ml_xm.h] - (193 bytes)

    #ifndef ml_xm_h_n4378789243234890
    #define ml_xm_h_n4378789243234890

    #include <mpl/mp_xm.h>

    int mpl__xm_load(vbf_t *file, mpl__xm_t *xm);
    int mpl__xm_destruct(mpl__xm_t *xm);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/dsp_std.h] - (484 bytes)

    #ifndef dsp_std_h_n43782784923
    #define dsp_std_h_n43782784923

    #include <mpl/snddev.h>

    int mpl__dsp_add(void *src, void *dst, int size, int ch_num, float32 vol, int format);
    int mpl__dsp_sub(void *src, void *dst, int size, int ch_num, float32 vol, int format);
    int mpl__dsp_move(void *src, void *dst, int size, int ch_num, float32 vol, int format);
    int mpl__dsp_conv_format(void *src, void *dst, int src_format, int dst_format, int size, int ch_num, float32 vol);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/mx_std.h] - (1,461 bytes)

    #ifndef mx_std_h_n37842789342789
    #define mx_std_h_37842789342789

    // standard mixer

    #include <mpl/mx.h>

    typedef struct {
    	int					exists;
    	mpl__snd_mixer_smp_t smp;
    	int					sus_loop_beg;
    	int					sus_loop_end;
    	int					sus_loop_mode;
    //	int					locked;
    } mpl__mx_std_smp_t;

    typedef struct {
    	int					playing;
    	int					smp;
    	float32				patch[8];
    	float32				vol_left, vol_right, vol_center;
    	float32				vol_left_ramp, vol_right_ramp, vol_center_ramp;
    	int					vol_left_ramp_num, vol_right_ramp_num, vol_center_ramp_num;
    	float32				vol_left_dst, vol_right_dst, vol_center_dst;
    	float32				vol, pan_lr;
    	float32				freq;
    	float64				pos;
    	int					dir;
    	int					loop_beg;
    	int					loop_end;
    	int					loop_mode;
    } mpl__mx_std_ch_t;

    typedef struct {
    	mpl__mx_std_smp_t	*smp;
    	int					smp_num;
    	mpl__mx_std_ch_t	*ch;
    	int					ch_num;

    	int					latency;
    	int					paused;
    	int					mem_usage;
    	int					qual;
    	mpl__snd_dev_output_t output;
    	float32				vol_local;
    	float32				pan_lr_local;
    	float32				pan_fb_local;
    	float32				vol_global;
    	float32				pan_lr_global;
    	float32				pan_fb_global;

    	float32				ramp;
    	float32				dc_spd[2], dc_pos[2];
    //	float32				quant[2];

    	mpl__snd_mixer_t	iface;
    	mpl__snd_call_back_t call_back;
    	float64				count_down_frac;
    	int					count_down;
    } mpl__mx_std_t;

    int  mpl__mx_std_create(mpl__mixer_t **mixer);
    void mpl__mx_std_destroy(mpl__mixer_t *mixer);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/sys/critsect.h] - (502 bytes)

    #ifndef critsect_h_n423784238
    #define critsect_h_n423784238

    #include <windows.h>
    #include <sys_cfg.h>
    #include <mpl/error.h>

    typedef CRITICAL_SECTION mpl__critical_section_t;

    int mpl__cs_create(mpl__critical_section_t **cs);
    int mpl__cs_destroy(mpl__critical_section_t *cs);
    int mpl__cs_construct(mpl__critical_section_t *cs);
    int mpl__cs_destruct(mpl__critical_section_t *cs);
    int mpl__cs_enter(mpl__critical_section_t *cs);
    int mpl__cs_leave(mpl__critical_section_t *cs);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/sys/mem.h] - (510 bytes)

    #ifndef mem_h_n78923478924
    #define mem_h_n78923478924

    #include <sys_cfg.h>
    #include <mpl/error.h>

    typedef int mpl__mem_size_t;

    int mpl__mem_init();
    int mpl__mem_alloc(mpl__mem_size_t size, void **mem);
    int mpl__mem_get_size(mpl__mem_size_t *size, void *mem);
    int mpl__mem_resize(mpl__mem_size_t newsize, int onlyexpand, void **mem);
    int mpl__mem_free(void *mem);
    int mpl__mem_copy(void *src, void *dst, mpl__mem_size_t size);
    int mpl__mem_set_zero(void *mem, mpl__mem_size_t size);

    #endif

Currently browsing [playxm.zip] (61,482 bytes) - [playxm/inc/mpl/sys/msg_box.h] - (760 bytes)

    #ifndef msg_box_h_n43789423798
    #define msg_box_h_n43789423798

    #include <sys_cfg.h>
    #include <mpl/sys/critsect.h>
    #include <mpl/error.h>

    typedef struct mpl__msg_s {
    	int					msg;
    	int					param[8];
    	void				*data;
    } mpl__msg_t;

    typedef struct mpl__msg_box_s {
    	mpl__msg_t				*msg;
    	int						max;
    	int						cnt;
    	int						first;
    	int						last;
    	mpl__critical_section_t	cs;
    } mpl__msg_box_t;

    int mpl__msg_box_create(mpl__msg_box_t **mb, int max);
    int mpl__msg_box_destroy(mpl__msg_box_t *mb);
    int mpl__msg_box_construct(mpl__msg_box_t *mb, int max);
    int mpl__msg_box_destruct(mpl__msg_box_t *mb);
    int mpl__msg_box_send(mpl__msg_box_t *mb, mpl__msg_t *msg);
    int mpl__msg_box_receive(mpl__msg_box_t *mb, mpl__msg_t *msg);

    #endif

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.