int main() { output_file = fopen("output.wav", "wb"); if (!output_file) die_perror("failed to open file"); int samplerate = SAMPLE_RATE; int channels = 2; int bitspersample = 16; int datarate = samplerate * channels * (bitspersample / 8); int blockalign = channels * (bitspersample / 8); // write wav header output_write("RIFF", 4); long riff_len_pos = ftell(output_file); // need to write 36+datalen to riff_len_pos write_le32(0); output_write("WAVE", 4); output_write("fmt ", 4); write_le32(16); write_le16(1); write_le16(channels); write_le32(samplerate); write_le32(datarate); write_le16(blockalign); write_le16(bitspersample); output_write("data", 4); long wav_data_pos = ftell(output_file); // need to write datalen to wav_data_pos write_le32(0); int i; for (i = 0; i < 22050; i++) output_sample(0, 0); // write 500ms of silence write_pulse(1, 4909, 1000000); // command start write_pulse(0, 4320, 1000000); i = 0; unsigned code = 0xe0e040bf; for (i = 0; i < 32; i++) { int bit = (code >> (31 - i)) & 0x1; if (bit) { write_pulse(1, 818, 1000000); // 1 bit write_pulse(0, 1425, 1000000); } else { write_pulse(1, 818, 1000000); // 0 bit write_pulse(0, 325, 1000000); } } write_pulse(1, 717, 1000000); // command stop write_pulse(0, 717, 1000000); for (i = 0; i < 22050; i++) output_sample(0, 0); // write 500ms of silence fseek(output_file, riff_len_pos, SEEK_SET); write_le32(36 + datalen); fseek(output_file, wav_data_pos, SEEK_SET); write_le32(datalen); fclose(output_file); return 0; }
/* Convert RLE block to a TZX DRB as TZX CSW block support is limited :/ */ static libspectrum_error tzx_write_rle( libspectrum_tape_block *block, libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length, libspectrum_tape *tape, libspectrum_tape_iterator iterator ) { libspectrum_error error; libspectrum_tape_block_state it; libspectrum_dword scale = libspectrum_tape_block_scale( block ); libspectrum_dword pulse_tstates = 0; libspectrum_dword balance_tstates = 0; int flags = 0; libspectrum_tape_block *raw_block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RAW_DATA ); libspectrum_tape_block_set_bit_length( raw_block, scale ); libspectrum_tape_block_set_pause ( raw_block, 0 ); rle_state.bits_used = 0; rle_state.level = 0; rle_state.length = 0; rle_state.tape_length = 8192; rle_state.tape_buffer = libspectrum_malloc( rle_state.tape_length ); *rle_state.tape_buffer = 0; it.current_block = iterator; error = libspectrum_tape_block_init( block, &it ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } while( !(flags & LIBSPECTRUM_TAPE_FLAGS_BLOCK) ) { libspectrum_dword pulse_length = 0; /* Use internal version of this that doesn't bugger up the external tape status */ error = libspectrum_tape_get_next_edge_internal( &pulse_tstates, &flags, tape, &it ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } balance_tstates += pulse_tstates; /* next set of pulses is: balance_tstates / scale; */ pulse_length = balance_tstates / scale; balance_tstates = balance_tstates % scale; /* write pulse_length bits of the current level into the buffer */ write_pulse( pulse_length ); } if( rle_state.length || rle_state.bits_used ) { if( rle_state.bits_used ) { rle_state.length++; } else { rle_state.bits_used = 8; } error = libspectrum_tape_block_set_bits_in_last_byte( raw_block, rle_state.bits_used ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } error = libspectrum_tape_block_set_data_length( raw_block, rle_state.length ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } error = libspectrum_tape_block_set_data( raw_block, rle_state.tape_buffer ); if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( rle_state.tape_buffer ); libspectrum_tape_block_free( raw_block ); return error; } /* now have tzx_write_raw_data finish the job */ tzx_write_raw_data( raw_block, buffer, ptr, length ); } else { libspectrum_free( rle_state.tape_buffer ); } return libspectrum_tape_block_free( raw_block ); }