Index: /libmpc/branches/r2d/mpcgain/mpcgain.c
===================================================================
--- /libmpc/branches/r2d/mpcgain/mpcgain.c	(revision 182)
+++ /libmpc/branches/r2d/mpcgain/mpcgain.c	(revision 183)
@@ -33,6 +33,17 @@
 */
 #include <stdio.h>
+#include <math.h>
 #include <mpcdec/mpcdec.h>
+#include <mpc/minimax.h>
 #include <replaygain/gain_analysis.h>
+
+#include "../libmpcdec/internal.h"
+
+// mpc_bits_reader.c
+int mpc_bits_get_block(mpc_bits_reader * r, mpc_block * p_block);
+unsigned int mpc_bits_get_size(mpc_bits_reader * r, mpc_uint64_t * p_size);
+
+// crc32.c
+unsigned long crc32(unsigned char *buf, int len);
 
 static void usage(const char *exename)
@@ -48,4 +59,10 @@
 	mpc_status err;
 	MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH];
+	MPC_SAMPLE_FORMAT album_max = 0;
+	mpc_uint16_t album_gain;
+	mpc_uint16_t album_peak;
+	mpc_uint16_t * title_gain;
+	mpc_uint16_t * title_peak;
+	mpc_uint32_t * header_pos;
 	Float_t left_samples[MPC_FRAME_LENGTH * sizeof(Float_t)];
 	Float_t right_samples[MPC_FRAME_LENGTH * sizeof(Float_t)];
@@ -57,5 +74,11 @@
 	}
 
+	title_gain = malloc((sizeof(mpc_uint16_t) * 2 + sizeof(mpc_uint32_t)) * (argc - 1));
+	title_peak = title_gain + (argc - 1);
+	header_pos = (mpc_uint32_t *) (title_peak + (argc - 1));
+
 	for( j = 1; j < argc; j++){
+		MPC_SAMPLE_FORMAT title_max = 0;
+
 		err = mpc_reader_init_stdio(&reader, argv[j]);
 		if(err < 0) return !MPC_STATUS_OK;
@@ -78,4 +101,6 @@
 				left_samples[i] = sample_buffer[2 * i] * (1 << 15);
 				right_samples[i] = sample_buffer[2 * i + 1] * (1 << 15);
+				title_max = maxf(title_max, sample_buffer[2 * i]);
+				title_max = maxf(title_max, sample_buffer[2 * i + 1]);
 			}
 
@@ -83,5 +108,9 @@
 		}
 
-		printf("%s : %f\n", argv[j], GetTitleGain());
+		title_gain[j-1] = (mpc_uint16_t) (GetTitleGain() * 256);
+		title_peak[j-1] = (mpc_uint16_t) (log10(title_max * (1 << 15)) * 20 * 256);
+		header_pos[j-1] = si.header_position + 4;
+
+		album_max = maxf(album_max, title_max);
 
 		mpc_demux_exit(demux);
@@ -89,5 +118,68 @@
 	}
 
-	printf("album : %f\n", GetAlbumGain());
+	album_gain = (mpc_uint16_t) (GetAlbumGain() * 256);
+	album_peak = (mpc_uint16_t) (log10(album_max * (1 << 15)) * 20 * 256);
+
+	for( j = 0; j < argc - 1; j++) {
+		unsigned char buffer[64];
+		mpc_bits_reader r;
+		mpc_block b;
+		mpc_uint64_t size;
+		mpc_uint32_t crc_pos, crc;
+		FILE * file;
+
+		file = fopen( argv[j + 1], "r+");
+		fseek(file, header_pos[j] - 4, SEEK_SET);
+		fread(buffer, 1, 16, file);
+		if (memcmp(buffer, "MPCK", 4) != 0) {
+			fprintf(stderr, "Unsupported file format, not a sv8 file : %s\n", argv[j + 1]);
+			fclose(file);
+			continue;
+		}
+		r.buff = buffer + 4;
+		r.count = 8;
+
+		size = mpc_bits_get_block(&r, &b);
+
+		while( memcmp(b.key, "SI", 2) != 0 ) {
+			header_pos[j] += b.size;
+			fseek(file, header_pos[j], SEEK_SET);
+			fread(buffer, 1, 16, file);
+			r.buff = buffer;
+			r.count = 8;
+			size = mpc_bits_get_block(&r, &b);
+		}
+
+		header_pos[j] += size;
+
+		fread(buffer + 16, 1, 48, file);
+
+		crc_pos = r.buff - buffer + (8 > r.count); // save position of CRC
+		r.buff += 4; // skip CRC
+		mpc_bits_get_size(&r, &size);
+		size += 4 + crc_pos;
+
+		buffer[size] = 1; // replaygain version
+		buffer[size + 1] = title_gain[j] >> 8;
+		buffer[size + 2] = title_gain[j] & 0xFF;
+		buffer[size + 3] = title_peak[j] >> 8;
+		buffer[size + 4] = title_peak[j] & 0xFF;
+		buffer[size + 5] = album_gain >> 8;
+		buffer[size + 6] = album_gain & 0xFF;
+		buffer[size + 7] = album_peak >> 8;
+		buffer[size + 8] = album_peak & 0xFF;
+
+		crc = crc32(buffer + crc_pos + 4, (int)b.size - 4);
+		buffer[crc_pos] = crc >> 24;
+		buffer[crc_pos + 1] = (crc >> 16) & 0xFF;
+		buffer[crc_pos + 2] = (crc >> 8) & 0xFF;
+		buffer[crc_pos + 3] = crc & 0xFF;
+
+		fseek(file, header_pos[j], SEEK_SET);
+		fwrite(buffer + crc_pos, 1, b.size, file);
+		fclose(file);
+	}
+
+	free(title_gain);
 
     return 0;
