Mercurial > hg > dmlib
view minijss/jssmod.c @ 2064:3617ef01c1de
Separate ILBM and PBM subformats of IFF images.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 05 Dec 2018 13:31:59 +0200 |
parents | 2f8506171064 |
children | 40ccc09f09be |
line wrap: on
line source
/* * miniJSS - Module structure and handling routines * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2006-2015 Tecnic Software productions (TNSP) */ #include "jssmod.h" #ifndef JSS_LIGHT /* Take given data until maxlen reached, make a string. * Basically a bit like strndup(), except end marker byte * can be specified. */ char *jssASCIItoStr(const char * src, const char endByte, const size_t len) { size_t i, k; char *res; for (i = 0; src[i] != endByte && i < len; ) i++; if ((res = dmMalloc(i + 1)) == NULL) return NULL; for (k = 0; src[k] != endByte && k < i; k++) res[k] = src[k]; res[k] = 0; return res; } /* Encodes a given 8-bit sample */ int jssEncodeSample8(Uint8 * data, const size_t len, const int ops) { Sint8 value = 0; for (size_t offs = 0; offs < len; offs++) { Sint8 t = data[offs]; if (ops & jsampFlipSign) t ^= 0x80; if (ops & jsampDelta) { int n = t - value; value = t; t = n; } data[offs] = t; } return DMERR_OK; } /* Decodes a given 16-bit sample */ int jssEncodeSample16(Uint16 * data, const size_t len, const int ops) { // "Split" the 16-bit samples into 8-bit halves if (ops & jsampSplit) { // Allocate temporary processing buffer Uint8 *bp1, *bp2; size_t bufSize = len * sizeof(Sint16); Sint16 *tmpBuf; if ((tmpBuf = dmMalloc(bufSize)) == NULL) return DMERR_MALLOC; bp1 = (Uint8 *) data; bp2 = bp1 + len; for (size_t offs = 0; offs < len; offs++) { const Sint16 t = tmpBuf[offs]; bp1[offs] = t >> 8; bp2[offs] = t & 0xff; } memcpy(data, tmpBuf, bufSize); dmFree(tmpBuf); return jssEncodeSample8((Uint8 *) data, bufSize, ops); } else { Sint16 value = 0, *sdata = (Sint16 *) data; for (size_t offs = 0; offs < len; offs++) { Sint16 t; if (ops & jsampSwapEndianess) { const Sint16 p = sdata[offs]; t = ((p >> 8) & 0xff) | ((p & 0xff) << 8); } else t = sdata[offs]; if (ops & jsampDelta) { const int n = t - value; value = t; t = n; } if (ops & jsampFlipSign) t ^= 0x8000; sdata[offs] = t; } } return DMERR_OK; } #endif /* Decodes a given 8-bit sample */ int jssDecodeSample8(Uint8 * data, const size_t len, const int ops) { Sint8 value = 0; for (size_t offs = 0; offs < len; offs++) { Sint8 t = data[offs]; if (ops & jsampDelta) t = value = t + value; if (ops & jsampFlipSign) t ^= 0x80; data[offs] = t; } return DMERR_OK; } /* Decodes a given 16-bit sample */ int jssDecodeSample16(Uint16 * data, const size_t len, const int ops) { if (ops & jsampSplit) { size_t bufSize = len * sizeof(Uint16); Uint8 *bp1, *bp2; Sint16 *tmpBuf; int ret; if ((ret = jssDecodeSample8((Uint8 *) data, bufSize, ops)) != DMERR_OK) return ret; if ((tmpBuf = dmMalloc(bufSize)) == NULL) return DMERR_MALLOC; // Copy original data to temporary buffer memcpy(tmpBuf, data, bufSize); bp1 = (Uint8 *) tmpBuf; bp2 = bp1 + len; for (size_t offs = 0; offs < len; offs++) { data[offs] = (bp1[offs] << 8) | (bp2[offs] & 0xff); } dmFree(tmpBuf); } else { Sint16 value = 0, *sdata = (Sint16 *) data; for (size_t offs = 0; offs < len; offs++) { Sint16 t; if (ops & jsampSwapEndianess) { const Sint16 p = sdata[offs]; t = ((p >> 8) & 0xff) | ((p & 0xff) << 8); } else t = sdata[offs]; if (ops & jsampDelta) t = value = t + value; if (ops & jsampFlipSign) t ^= 0x8000; sdata[offs] = t; } } return DMERR_OK; } /* Convert sample data from U8 to S16 */ int jssConvertSampleTo16(void **dst, void * src, const size_t len) { Uint8 *in = (Uint8 *) src; Sint16 *out; if ((*dst = out = dmMalloc(sizeof(Sint16) * len)) == NULL) return DMERR_MALLOC; for (size_t offs = 0; offs < len; offs++) { out[offs] = (in[offs] * 256) - 32768; } return DMERR_OK; } /* Converts the given module in preparation for playing it. * This involves sample format conversion (8 to 16 bit, etc.) * * NOTICE! The converted module can only be saved in JSSMOD * format, but this is not recommended. */ int jssConvertModuleForPlaying(JSSModule *module) { if (module == NULL) return DMERR_NULLPTR; // Convert instruments for (int i = 0; i < module->ninstruments; i++) { JSSInstrument *inst = module->instruments[i]; if (inst != NULL && inst->data != NULL) { int res; void *data = NULL; if (inst->flags & jsf16bit) continue; if ((res = jssConvertSampleTo16(&data, inst->data, inst->size)) != DMERR_OK) return res; inst->flags |= jsf16bit; dmFree(inst->data); inst->data = data; } } return DMERR_OK; } /* Allocates a new module structure or returns errorvalue if failed. * Memory is allocated only for the basic structure. Sample- and pattern * areas must be allocated separately with appropriate routines. */ JSSModule *jssAllocateModule(void) { JSSModule *module; // Allocate module structure module = dmMalloc0(sizeof(JSSModule)); if (module == NULL) return NULL; // Initialize structure for (int i = 0; i < jsetNChannels; i++) module->defPanning[i] = jchPanMiddle; for (int i = 0; i < jsetMaxOrders; i++) module->orderList[i] = jsetOrderEnd; // Allocate mutex #ifdef JSS_SUP_THREADS module->mutex = dmCreateMutex(); #endif return module; } /* Frees a given module structure, freeing all memory areas * that were allocated for it (including patterns, samples, etc.) */ int jssFreeModule(JSSModule * module) { if (module == NULL) return DMERR_NULLPTR; // Free strings #ifndef JSS_LIGHT dmFree(module->moduleName); dmFree(module->trackerName); #endif // Free patterns for (int i = 0; i < module->npatterns; i++) jssFreePattern(module->patterns[i]); // Free the "empty" pattern jssFreePattern(module->patterns[jsetMaxPatterns]); // Free instruments for (int i = 0; i < module->ninstruments; i++) jssFreeInstrument(module->instruments[i]); // Free extended instruments for (int i = 0; i < module->nextInstruments; i++) jssFreeExtInstrument(module->extInstruments[i]); // Free mutex #ifdef JSS_SUP_THREADS dmDestroyMutex(module->mutex); #endif // Free the module structure dmMemset(module, 0, sizeof(JSSModule)); dmFree(module); return DMERR_OK; } /* Allocates and initializes a internal pattern structure. */ JSSPattern *jssAllocatePattern(const int nrows, const int nchannels) { JSSPattern *pattern; JSSNote *pnote; // Check arguments if (nrows <= 0 || nchannels <= 0) JSSERROR(DMERR_INVALID_ARGS, NULL, "Invalid nrows=%i or nchannels=%i.\n", nrows, nchannels); // Allocate a pattern structure if ((pattern = dmMalloc0(sizeof(JSSPattern))) == NULL) JSSERROR(DMERR_MALLOC, NULL, "Could not allocate pattern structure.\n"); // Allocate notedata pattern->data = dmMalloc(nrows * nchannels * sizeof(JSSNote)); if (pattern->data == NULL) { dmFree(pattern); JSSERROR(DMERR_MALLOC, NULL, "Could not allocate pattern data (nrows=%i, nchannels=%i).\n", nrows, nchannels); } // Initialize structure pattern->nrows = nrows; pattern->nchannels = nchannels; pnote = pattern->data; for (int row = 0; row < nrows; row++) for (int chn = 0; chn < nchannels; chn++) { pnote->note = pnote->instrument = pnote->volume = pnote->effect = pnote->param = jsetNotSet; pnote++; } return pattern; } void jssFreePattern(JSSPattern *pattern) { if (pattern != NULL) { dmFree(pattern->data); dmFree(pattern); } } /* Allocates and initializes internal "normal" instrument structure. */ JSSInstrument *jssAllocateInstrument(void) { JSSInstrument *inst; // Allocate a instrument structure if ((inst = dmMalloc0(sizeof(JSSInstrument))) == NULL) return NULL; return inst; } void jssFreeInstrument(JSSInstrument *inst) { if (inst != NULL) { #ifndef JSS_LIGHT dmFree(inst->desc); #endif dmFree(inst->data); dmFree(inst); } } /* Allocates and initializes "extended" instrument structure. */ JSSExtInstrument *jssAllocateExtInstrument(void) { JSSExtInstrument *inst; // Allocate a instrument structure if ((inst = dmMalloc0(sizeof(JSSExtInstrument))) == NULL) return NULL; // Initialize the requisite fields for (int i = 0; i < jsetNNotes; i++) inst->sNumForNotes[i] = jsetNotSet; return inst; } void jssFreeExtInstrument(JSSExtInstrument *inst) { if (inst != NULL) { #ifndef JSS_LIGHT dmFree(inst->desc); #endif dmFree(inst->instConvTable); dmFree(inst); } }