Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

PC speaker sound support. Yep.

  • Loading branch information...
commit 1f9a6f339b15fe1f505e7ebc7dd193b956bbc0bf 1 parent 8a9270e
Gaerzi authored
1  dist/res/config/entry_types/types_audio.txt
@@ -166,6 +166,7 @@ entry_types
166 166
 		format = snd_speaker;
167 167
 		export_ext = "lmp";
168 168
 		reliability = 100;
  169
+		editor = audio;
169 170
 	}
170 171
 
171 172
 	snd_wav : sound
4  src/ArchivePanel.cpp
@@ -1871,6 +1871,9 @@ bool ArchivePanel::dSndWavConvert()
1871 1871
 		if (selection[a]->getType()->getFormat() == "snd_doom" ||
1872 1872
 		        selection[a]->getType()->getFormat() == "snd_doom_mac")
1873 1873
 			worked = Conversions::doomSndToWav(selection[a]->getMCData(), wav);
  1874
+		// Or Doom Speaker sound format
  1875
+		else if (selection[a]->getType()->getFormat() == "snd_speaker")
  1876
+			worked = Conversions::spkSndToWav(selection[a]->getMCData(), wav);
1874 1877
 		// Or Jaguar Doom sound format
1875 1878
 		else if (selection[a]->getType()->getFormat() == "snd_jaguar")
1876 1879
 			worked = Conversions::jagSndToWav(selection[a]->getMCData(), wav);
@@ -2718,6 +2721,7 @@ void ArchivePanel::onEntryListRightClick(wxListEvent& e)
2718 2721
 		if (!dsnd_selected)
2719 2722
 		{
2720 2723
 			if (selection[a]->getType()->getFormat() == "snd_doom" ||
  2724
+			        selection[a]->getType()->getFormat() == "snd_speaker" ||
2721 2725
 			        selection[a]->getType()->getFormat() == "snd_wolf" ||
2722 2726
 			        selection[a]->getType()->getFormat() == "snd_doom_mac" ||
2723 2727
 			        selection[a]->getType()->getFormat() == "snd_jaguar" ||
8  src/AudioEntryPanel.cpp
@@ -211,6 +211,8 @@ bool AudioEntryPanel::open()
211 211
 	if (entry->getType()->getFormat() == "snd_doom" ||			// Doom Sound -> WAV
212 212
 	        entry->getType()->getFormat() == "snd_doom_mac")
213 213
 		Conversions::doomSndToWav(mcdata, convdata);
  214
+	else if (entry->getType()->getFormat() == "snd_speaker")	// Doom PC Speaker Sound -> WAV
  215
+		Conversions::spkSndToWav(mcdata, convdata);
214 216
 	else if (entry->getType()->getFormat() == "snd_wolf")		// Wolfenstein 3D Sound -> WAV
215 217
 		Conversions::wolfSndToWav(mcdata, convdata);
216 218
 	else if (entry->getType()->getFormat() == "snd_voc")		// Creative Voice File -> WAV
@@ -284,7 +286,7 @@ bool AudioEntryPanel::openAudio(MemChunk& audio, string filename)
284 286
 	// Load into buffer
285 287
 	if (sound_buffer->loadFromMemory((const char*)audio.getData(), audio.getSize()))
286 288
 	{
287  
-		wxLogMessage("opened as sound");
  289
+		LOG_MESSAGE(3, "opened as sound");
288 290
 		// Bind to sound
289 291
 		sound.setBuffer(*sound_buffer);
290 292
 		audio_type = AUTYPE_SOUND;
@@ -299,13 +301,13 @@ bool AudioEntryPanel::openAudio(MemChunk& audio, string filename)
299 301
 	}
300 302
 	else if (music.openFromMemory((const char*)audio.getData(), audio.getSize()))
301 303
 	{
302  
-		wxLogMessage("opened as music");
  304
+		LOG_MESSAGE(3, "opened as music");
303 305
 		// Couldn't open the audio as a sf::SoundBuffer, try sf::Music instead
304 306
 		audio_type = AUTYPE_MUSIC;
305 307
 
306 308
 		// Enable play controls
307 309
 		setAudioDuration(music.getDuration().asMilliseconds());
308  
-		wxLogMessage("duration: %dms", music.getDuration().asMilliseconds());
  310
+		//wxLogMessage("duration: %dms", music.getDuration().asMilliseconds());
309 311
 		btn_play->Enable();
310 312
 		btn_stop->Enable();
311 313
 
134  src/Conversions.cpp
@@ -29,6 +29,7 @@
29 29
  *******************************************************************/
30 30
 #include "Main.h"
31 31
 #include "Archive.h"
  32
+#include "MathStuff.h"
32 33
 #include "Conversions.h"
33 34
 #include "ArchiveEntry.h"
34 35
 #include "mus2mid/mus2mid.h"
@@ -80,6 +81,13 @@ struct jsnd_header_t
80 81
 	uint32_t decay;
81 82
 };
82 83
 
  84
+// For speaker sound conversion
  85
+struct spksnd_header_t
  86
+{
  87
+	uint16_t zero;
  88
+	uint16_t samples;
  89
+};
  90
+
83 91
 /*******************************************************************
84 92
  * FUNCTIONS
85 93
  *******************************************************************/
@@ -699,3 +707,129 @@ bool Conversions::gmidToMidi(MemChunk& in, MemChunk& out)
699 707
 
700 708
 	return true;
701 709
 }
  710
+
  711
+/* Conversions::spkSndToWav
  712
+ * Converts Doom PC speaker sound data [in] to wav format, written 
  713
+ * to [out]
  714
+ *******************************************************************/
  715
+#define ORIG_RATE 140.0
  716
+#define FACTOR 315	// 315*140 = 44100
  717
+#define FREQ 1193170.0
  718
+#define RATE (ORIG_RATE * FACTOR)
  719
+uint16_t counters[128] =
  720
+{
  721
+	   0, 6818, 6628, 6449, 6279, 6087, 5906, 5736,
  722
+	5575, 5423, 5279, 5120, 4971, 4830, 4697, 4554,
  723
+	4435, 4307, 4186, 4058, 3950, 3836, 3728, 3615,
  724
+	3519, 3418, 3323, 3224, 3131, 3043, 2960, 2875,
  725
+	2794, 2711, 2633, 2560, 2485, 2415, 2348, 2281,
  726
+	2213, 2153, 2089, 2032, 1975, 1918, 1864, 1810,
  727
+	1757, 1709, 1659, 1612, 1565, 1521, 1478, 1435,
  728
+	1395, 1355, 1316, 1280, 1242, 1207, 1173, 1140,
  729
+	1107, 1075, 1045, 1015,  986,  959,  931,  905,
  730
+	 879,  854,  829,  806,  783,  760,  739,  718,
  731
+	 697,  677,  658,  640,  621,  604,  586,  570,
  732
+	 553,  538,  522,  507,  493,  479,  465,  452,
  733
+	 439,  427,  415,  403,  391,  380,  369,  359,
  734
+	 348,  339,  329,  319,  310,  302,  293,  285,
  735
+	 276,  269,  261,  253,  246,  239,  232,  226,
  736
+	 219,  213,  207,  201,  195,  190,  184,  179
  737
+};
  738
+bool Conversions::spkSndToWav(MemChunk& in, MemChunk& out)
  739
+{
  740
+	// --- Read Doom sound ---
  741
+
  742
+	// Read doom sound header
  743
+	spksnd_header_t header;
  744
+	in.seek(0, SEEK_SET);
  745
+	in.read(&header, 4);
  746
+
  747
+	// Format checks
  748
+	if (header.zero != 0)  	// Check for magic number
  749
+	{
  750
+		Global::error = "Invalid Doom PC Speaker Sound";
  751
+		return false;
  752
+	}
  753
+	if (header.samples > (in.getSize() - 4) || header.samples <= 4)  	// Check for sane values
  754
+	{
  755
+		Global::error = "Invalid Doom PC Speaker Sound";
  756
+		return false;
  757
+	}
  758
+
  759
+	// Read samples
  760
+	uint8_t* osamples = new uint8_t[header.samples];
  761
+	uint8_t* nsamples = new uint8_t[header.samples*FACTOR];
  762
+	in.read(osamples, header.samples);
  763
+
  764
+	// Convert counter values to sample values
  765
+	for (int s = 0; s < header.samples; ++s)
  766
+	{
  767
+		if (osamples[s] > 127)
  768
+		{
  769
+			wxLogMessage("Invalid PC Speaker counter value: %d > 127", osamples[s]);
  770
+			delete[] osamples;
  771
+			delete[] nsamples;
  772
+			return false;
  773
+		}
  774
+		if (osamples[s] > 0)
  775
+		{
  776
+			// First, convert counter value to frequency in Hz
  777
+			double f = FREQ / (double)counters[osamples[s]];
  778
+			//double f = FREQ / (440.0 * pow((double)2.0, (96-osamples[s])/24));
  779
+
  780
+			// Then write a bunch of samples because WAVs at 140 Hz
  781
+			// just plain don't work at all -- I know, I tried.
  782
+			for (int i = 0; i < FACTOR; ++i)
  783
+			{
  784
+				// Finally, convert frequency into sample value
  785
+				int pos = (s*FACTOR) + i;
  786
+				double time   = (double)pos/(double)RATE;
  787
+				double sample = 1.0 + sin(time * 2.0 * PI * f);
  788
+				nsamples[pos] = (uint8_t)(sample*128.0);
  789
+			}
  790
+		}
  791
+		else memset(nsamples + (s*FACTOR), 0, FACTOR);
  792
+	}
  793
+
  794
+	// --- Write WAV ---
  795
+
  796
+	wav_chunk_t whdr, wdhdr;
  797
+	wav_fmtchunk_t fmtchunk;
  798
+
  799
+	// Setup data header
  800
+	char did[4] = { 'd', 'a', 't', 'a' };
  801
+	memcpy(&wdhdr.id, &did, 4);
  802
+	wdhdr.size = header.samples * FACTOR;
  803
+
  804
+	// Setup fmt chunk
  805
+	char fid[4] = { 'f', 'm', 't', ' ' };
  806
+	memcpy(&fmtchunk.header.id, &fid, 4);
  807
+	fmtchunk.header.size = 16;
  808
+	fmtchunk.tag = 1;
  809
+	fmtchunk.channels = 1;
  810
+	fmtchunk.samplerate = RATE;
  811
+	fmtchunk.datarate = RATE;
  812
+	fmtchunk.blocksize = 1;
  813
+	fmtchunk.bps = 8;
  814
+
  815
+	// Setup main header
  816
+	char wid[4] = { 'R', 'I', 'F', 'F' };
  817
+	memcpy(&whdr.id, &wid, 4);
  818
+	whdr.size = wdhdr.size + fmtchunk.header.size + 8;
  819
+
  820
+	// Write chunks
  821
+	out.write(&whdr, 8);
  822
+	out.write("WAVE", 4);
  823
+	out.write(&fmtchunk, sizeof(wav_fmtchunk_t));
  824
+	out.write(&wdhdr, 8);
  825
+	out.write(nsamples, header.samples * FACTOR);
  826
+
  827
+	// Ensure data ends on even byte boundary
  828
+	if (header.samples % 2 != 0)
  829
+		out.write("\0", 1);
  830
+
  831
+	delete[] osamples;
  832
+	delete[] nsamples;
  833
+
  834
+	return true;
  835
+}
1  src/Conversions.h
@@ -7,6 +7,7 @@ class ArchiveEntry;
7 7
 namespace Conversions
8 8
 {
9 9
 	bool	wavToDoomSnd(MemChunk& in, MemChunk& out);
  10
+	bool	spkSndToWav(MemChunk& in, MemChunk& out);
10 11
 	bool	doomSndToWav(MemChunk& in, MemChunk& out);
11 12
 	bool	wolfSndToWav(MemChunk& in, MemChunk& out);
12 13
 	bool	jagSndToWav(MemChunk& in, MemChunk& out);

0 notes on commit 1f9a6f3

Please sign in to comment.
Something went wrong with that request. Please try again.