static void setup_tunnel(rpi_pixmap_decoder_t *rpd) { int dst_width, dst_height; OMX_PARAM_PORTDEFINITIONTYPE portdef; if(rpd->rpd_tunnel != NULL) return; OMX_INIT_STRUCTURE(portdef); portdef.nPortIndex = rpd->rpd_decoder->oc_outport; omxchk(OMX_GetParameter(rpd->rpd_decoder->oc_handle, OMX_IndexParamPortDefinition, &portdef)); pixmap_compute_rescale_dim(rpd->rpd_im, portdef.format.image.nFrameWidth, portdef.format.image.nFrameHeight, &dst_width, &dst_height); portdef.nPortIndex = rpd->rpd_resizer->oc_inport; omxchk(OMX_SetParameter(rpd->rpd_resizer->oc_handle, OMX_IndexParamPortDefinition, &portdef)); rpd->rpd_tunnel = omx_tunnel_create(rpd->rpd_decoder, rpd->rpd_decoder->oc_outport, rpd->rpd_resizer, rpd->rpd_resizer->oc_inport, "decoder -> resizer"); OMX_INIT_STRUCTURE(portdef); portdef.nPortIndex = rpd->rpd_resizer->oc_outport; omxchk(OMX_GetParameter(rpd->rpd_resizer->oc_handle, OMX_IndexParamPortDefinition, &portdef)); int stride = (dst_width * 4 + PIXMAP_ROW_ALIGN - 1) & ~(PIXMAP_ROW_ALIGN - 1); portdef.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused; portdef.format.image.eColorFormat = OMX_COLOR_Format32bitABGR8888; portdef.format.image.nFrameWidth = dst_width; portdef.format.image.nFrameHeight = dst_height; portdef.format.image.nStride = stride; portdef.format.image.nSliceHeight = 0; portdef.format.image.bFlagErrorConcealment = OMX_FALSE; omxchk(OMX_SetParameter(rpd->rpd_resizer->oc_handle, OMX_IndexParamPortDefinition, &portdef)); omxchk(OMX_GetParameter(rpd->rpd_resizer->oc_handle, OMX_IndexParamPortDefinition, &portdef)); omx_set_state(rpd->rpd_resizer, OMX_StateExecuting); omx_port_enable(rpd->rpd_resizer, rpd->rpd_resizer->oc_outport); pixmap_t *pm = rpd->rpd_pm = calloc(1, sizeof(pixmap_t)); pm->pm_refcount = 1; pm->pm_width = portdef.format.image.nFrameWidth; pm->pm_height = portdef.format.image.nFrameHeight; pm->pm_linesize = portdef.format.image.nStride; pm->pm_type = PIXMAP_BGR32; pm->pm_data = mymemalign(portdef.nBufferAlignment, portdef.nBufferSize); pm->pm_aspect = (float)pm->pm_width / (float)pm->pm_height; omxchk(OMX_UseBuffer(rpd->rpd_resizer->oc_handle, &rpd->rpd_buf, rpd->rpd_resizer->oc_outport, NULL, portdef.nBufferSize, pm->pm_data)); omx_wait_command(rpd->rpd_resizer); omxchk(OMX_FillThisBuffer(rpd->rpd_resizer->oc_handle, rpd->rpd_buf)); }
// Loads a song from memory and puts it in the song argument // returns 0 on success, an error code else u16 XMTransport::load_memory(const void *memory_file_begin, Song **_song) { MEMFILE_FILE *xmfile = MEMFILE_fopen(memory_file_begin); // // Read header // // Magic number char magicnumber[18] = {0}; MEMFILE_fread(magicnumber, 1, 17, xmfile); if( strcmp(magicnumber, "Extended Module: ") != 0 ) { MEMFILE_fclose(xmfile); return XM_TRANSPORT_ERROR_MAGICNUMBERINVALID; } // Song name char songname[21] = {0}; MEMFILE_fread(songname, 1, 20, xmfile); // Skip uninteresting stuff like tracker name and version MEMFILE_fseek(xmfile, 23, SEEK_CUR); // Header size u32 header_size; MEMFILE_fread(&header_size, 4, 1, xmfile); // Song length (pot size) u16 pot_size; MEMFILE_fread(&pot_size, 2, 1, xmfile); // Restart position u16 restart_pos; MEMFILE_fread(&restart_pos, 2, 1, xmfile); // Number of channels u16 n_channels; MEMFILE_fread(&n_channels, 2, 1, xmfile); // Number of patterns u16 n_patterns; MEMFILE_fread(&n_patterns, 2, 1, xmfile); // Number of instruments u16 n_inst; MEMFILE_fread(&n_inst, 2, 1, xmfile); // Flags, currently only used for the frequency table (0: amiga, 1: linear) // TODO: Amiga freq table u16 flags; MEMFILE_fread(&flags, 2, 1, xmfile); // Tempo u16 tempo; MEMFILE_fread(&tempo, 2, 1, xmfile); // BPM u16 bpm; MEMFILE_fread(&bpm, 2, 1, xmfile); // Construct the song with the current info Song *song = new Song(tempo, bpm, n_channels); song->setName(songname); song->setRestartPosition(restart_pos); // Pattern order table u8 i, potentry; MEMFILE_fread(&potentry, 1, 1, xmfile); song->setPotEntry(0, potentry); // The first entry is made automatically by the song for(i=1; i<pot_size; ++i) { MEMFILE_fread(&potentry, 1, 1, xmfile); song->potAdd(potentry); } MEMFILE_fseek(xmfile, 256-pot_size, SEEK_CUR); // // Read patterns // u8 pattern; for(pattern=0; pattern<n_patterns; ++pattern) { // Pattern header length u32 pattern_header_length; MEMFILE_fread(&pattern_header_length, 4, 1, xmfile); //iprintf("ptn header: %u\n",pattern_header_length); // Skip packing type (is always 0) MEMFILE_fseek(xmfile, 1, SEEK_CUR); // Number of rows u16 n_rows; MEMFILE_fread(&n_rows, 2, 1, xmfile); if(n_rows > MAX_PATTERN_LENGTH) { MEMFILE_fclose(xmfile); return XM_TRANSPORT_PATTERN_TOO_LONG; } // Packed patterndata size u16 patterndata_size; MEMFILE_fread(&patterndata_size, 2, 1, xmfile); //TODO: Handle empty patterns (which are left out in the xm format) if(patterndata_size > 0) { // Read the pattern u8 *ptn_data = (u8*)mymemalign(2, patterndata_size); u32 bytes_read; bytes_read = MEMFILE_fread(ptn_data, patterndata_size, 1, xmfile); if(bytes_read != patterndata_size) { MEMFILE_fclose(xmfile); return XM_TRANSPORT_ERROR_PATTERN_READ; } u32 ptn_data_offset = 0; u8 chn, magicbyte, note, inst, vol, eff_type, eff_param; u16 row; if(pattern>0) { song->addPattern(); } song->resizePattern(pattern, n_rows); Cell **ptn = song->getPattern(pattern); for(row=0; row<n_rows; ++row) { for(chn=0; chn<n_channels; ++chn) { magicbyte = ptn_data[ptn_data_offset]; ptn_data_offset++; //MEMFILE_fread(&magicbyte, 1, 1, xmfile); bool read_note=true, read_inst=true, read_vol=true, read_eff_type=true, read_eff_param=true; if(magicbyte & 1<<7) { // It's the magic byte! read_note = magicbyte & 1<<0; read_inst = magicbyte & 1<<1; read_vol = magicbyte & 1<<2; read_eff_type = magicbyte & 1<<3; read_eff_param = magicbyte & 1<<4; } else { // It's the note! note = magicbyte; read_note = false; } if(read_note) { note = ptn_data[ptn_data_offset]; ptn_data_offset++; } else { note = 0; } if(read_inst) { inst = ptn_data[ptn_data_offset]; ptn_data_offset++; } else { inst = NO_INSTRUMENT; } if(read_vol) { vol = ptn_data[ptn_data_offset]; ptn_data_offset++; } else { vol = 0; // 'Do nothing' } if(read_eff_type) { eff_type = ptn_data[ptn_data_offset]; ptn_data_offset++; } else { eff_type = 0; } if(read_eff_param) { eff_param = ptn_data[ptn_data_offset]; ptn_data_offset++; } else { eff_param = 0; } // Insert note into song if(note==0) { ptn[chn][row].note = EMPTY_NOTE; } else if(note==97) { ptn[chn][row].note = STOP_NOTE; } else { ptn[chn][row].note = note - 1; } if(inst != NO_INSTRUMENT) { ptn[chn][row].instrument = inst-1; // XM Inst indices start with 1 } else { ptn[chn][row].instrument = NO_INSTRUMENT; } if((vol >= 16) && (vol <= 80)) { u16 volume = (vol-16)*4; if(volume==256) volume = 255; ptn[chn][row].volume = volume; } else if(vol==0) { ptn[chn][row].volume = 255; } else { // TODO: Parse volume effects! } ptn[chn][row].effect = eff_type; ptn[chn][row].effect_param = eff_param; } } free(ptn_data); } else { // Make an empty pattern if(pattern > 0) { song->addPattern(); } song->resizePattern(pattern, n_rows); } } // // Read instruments // for(u8 inst=0; inst<n_inst; ++inst) { // Size u32 inst_size; MEMFILE_fread(&inst_size, 4, 1, xmfile); // Name char inst_name[23] = {0}; MEMFILE_fread(inst_name, 1, 22, xmfile); Instrument *instrument = new Instrument(inst_name); if(instrument == 0) { MEMFILE_fclose(xmfile); return XM_TRANSPORT_ERROR_MEMFULL; } song->setInstrument(inst, instrument); u8 useless_byte; //MEMFILE_fseek(xmfile, 1, SEEK_CUR); // Skip inst type as it is always 0 (maybe I could use this?) MEMFILE_fread(&useless_byte, 1, 1, xmfile); // Number of samples u16 inst_n_samples; MEMFILE_fread(&inst_n_samples, 2, 1, xmfile); if(inst_n_samples > 0) { // Sample header size u32 sample_header_size; MEMFILE_fread(&sample_header_size, 4, 1, xmfile); // Sample number for all notes u8 *note_sample_numbers = (u8*)mymemalign(2, 96); MEMFILE_fread(note_sample_numbers, 1, 96, xmfile); // Points for volume envelope u16 *volume_envelope = (u16*)mymemalign(2, 48); MEMFILE_fread(volume_envelope, 2, 24, xmfile); //MEMFILE_fseek(xmfile, 48, SEEK_CUR); // Skipped for now free(volume_envelope); // Points for panning envelope u8 *throwaway_bytes = (u8*)mymemalign(2, 48); //MEMFILE_fseek(xmfile, 48, SEEK_CUR); // Skipped for now MEMFILE_fread(throwaway_bytes, 1, 48, xmfile); free(throwaway_bytes); /* Various other things: Number of volume points Number of panning points Volume sustain point Volume loop start point Volume loop end point Panning sustain point Panning loop start point Panning loop end point Volume type: bit 0: On; 1: Sustain; 2: Loop Panning type: bit 0: On; 1: Sustain; 2: Loop Vibrato type Vibrato sweep Vibrato depth Vibrato rate Volume fadeout */ throwaway_bytes = (u8*)mymemalign(2, 16); //MEMFILE_fseek(xmfile, 16, SEEK_CUR); // Skipped for now MEMFILE_fread(throwaway_bytes, 1, 16, xmfile); free(throwaway_bytes); // Skip the rest of the header if is longer than the current position // This was really strange and took some time (and debugging with Tim) // to figure out. Why the fsck is the instrument header that much longer? // Well, don't care, skip it. if(inst_size>241) { throwaway_bytes = (u8*)mymemalign(2, inst_size-241); MEMFILE_fread(throwaway_bytes, 1, inst_size-241, xmfile); free(throwaway_bytes); } // Construct the instrument for(u8 i=0; i<96; ++i) { instrument->setNoteSample(i, note_sample_numbers[i]); } free(note_sample_numbers); // Load the sample(s) // Headers u8 *sample_headers = (u8*)mymemalign(2, inst_n_samples*40); MEMFILE_fread(sample_headers, 40, inst_n_samples, xmfile); for(u8 sample_id=0; sample_id<inst_n_samples; sample_id++) { // Sample length u32 sample_length; sample_length = *(u32*)(sample_headers+40*sample_id + 0); // Sample loop start u32 sample_loop_start; sample_loop_start = *(u32*)(sample_headers+40*sample_id + 4); // Sample loop length u32 sample_loop_length; sample_loop_length = *(u32*)(sample_headers+40*sample_id + 8); // Volume (0-64) u8 sample_volume; sample_volume = *(u8*)(sample_headers+40*sample_id + 12); if(sample_volume == 64) { // Convert scale to 0-255 sample_volume = 255; } else { sample_volume *= 4; } // Finetune s8 sample_finetune; sample_finetune = *(s8*)(sample_headers+40*sample_id + 13); // Type byte (loop type and wether it's 8 or 16 bit) u8 sample_type; sample_type = *(u8*)(sample_headers+40*sample_id + 14); u8 loop_type = sample_type & 3; bool sample_is_16_bit = sample_type & 0x10; // Panning u8 sample_panning; sample_panning = *(u8*)(sample_headers+40*sample_id + 15); // Relative note s8 sample_rel_note; sample_rel_note = *(s8*)(sample_headers+40*sample_id + 16); // Sample name char sample_name[23] = {0}; memcpy(sample_name, sample_headers+40*sample_id + 18, 22); // Sample data void *sample_data = mymemalign(2, sample_length); //mymemalign(2, sample_length); if(sample_data==NULL) { MEMFILE_fclose(xmfile); return XM_TRANSPORT_ERROR_MEMFULL; } MEMFILE_fread(sample_data, sample_length, 1, xmfile); //MEMFILE_fseek(xmfile, sample_length, SEEK_CUR); // Delta-decode if(sample_is_16_bit) { s16 last = 0; s16 *smp = (s16*)sample_data; for(u32 i=0; i<sample_length/2; ++i) { smp[i] += last; last = smp[i]; } } else { s8 last = 0; s8 *smp = (s8*)sample_data; for(u32 i=0; i<sample_length; ++i) { smp[i] += last; last = smp[i]; } } // Insert sample into the instrument u32 n_samples; if(sample_is_16_bit) { n_samples = sample_length/2; } else { n_samples = sample_length; } Sample *sample = new Sample(sample_data, n_samples, 8363, false, sample_is_16_bit, loop_type == 1, sample_volume); sample->setRelNote(sample_rel_note); sample->setFinetune(sample_finetune); sample->setLoopStart(sample_loop_start); sample->setLoopLength(sample_loop_length); instrument->addSample(sample); } free(sample_headers); } else { // If the instrument has no samples, skip the rest of the instrument header // (which should contain rubbish anyway) MEMFILE_fseek(xmfile, inst_size-29, SEEK_CUR); } } // // Finish up // MEMFILE_fclose(xmfile); // MATT - We have to destroy the old song! if (_song != NULL) { delete (*_song); } *_song = song; return 0; }