diff ym2612.c @ 1692:5dacaef602a7 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 05 Jan 2019 00:58:08 -0800
parents 804f13c090b4
children 5278b6e44fc1
line wrap: on
line diff
--- a/ym2612.c	Tue Dec 19 00:49:13 2017 -0800
+++ b/ym2612.c	Sat Jan 05 00:58:08 2019 -0800
@@ -116,12 +116,10 @@
 	}
 	log_context = NULL;
 }
-#define BUFFER_INC_RES 0x40000000UL
 
 void ym_adjust_master_clock(ym2612_context * context, uint32_t master_clock)
 {
-	uint64_t old_inc = context->buffer_inc;
-	context->buffer_inc = ((BUFFER_INC_RES * (uint64_t)context->sample_rate) / (uint64_t)master_clock) * (uint64_t)context->clock_inc * NUM_OPERATORS;
+	render_audio_adjust_clock(context->audio, master_clock, context->clock_inc * NUM_OPERATORS);
 }
 
 #ifdef __ANDROID__
@@ -137,6 +135,11 @@
 	memset(context->part1_regs, 0, sizeof(context->part1_regs));
 	memset(context->part2_regs, 0, sizeof(context->part2_regs));
 	memset(context->operators, 0, sizeof(context->operators));
+	FILE* savedlogs[NUM_CHANNELS];
+	for (int i = 0; i < NUM_CHANNELS; i++)
+	{
+		savedlogs[i] = context->channels[i].logfile;
+	}
 	memset(context->channels, 0, sizeof(context->channels));
 	memset(context->ch3_supp, 0, sizeof(context->ch3_supp));
 	context->selected_reg = 0;
@@ -155,6 +158,7 @@
 	//some games seem to expect that the LR flags start out as 1
 	for (int i = 0; i < NUM_CHANNELS; i++) {
 		context->channels[i].lr = 0xC0;
+		context->channels[i].logfile = savedlogs[i];
 	}
 	context->write_cycle = CYCLE_NEVER;
 	for (int i = 0; i < NUM_OPERATORS; i++) {
@@ -163,23 +167,13 @@
 	}
 }
 
-void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit, uint32_t options, uint32_t lowpass_cutoff)
+void ym_init(ym2612_context * context, uint32_t master_clock, uint32_t clock_div, uint32_t options)
 {
 	static uint8_t registered_finalize;
 	dfopen(debug_file, "ym_debug.txt", "w");
 	memset(context, 0, sizeof(*context));
-	context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2);
-	context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2);
-	context->sample_rate = sample_rate;
 	context->clock_inc = clock_div * 6;
-	ym_adjust_master_clock(context, master_clock);
-	
-	double rc = (1.0 / (double)lowpass_cutoff) / (2.0 * M_PI);
-	double dt = 1.0 / ((double)master_clock / (double)(context->clock_inc * NUM_OPERATORS));
-	double alpha = dt / (dt + rc);
-	context->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
-
-	context->sample_limit = sample_limit*2;
+	context->audio = render_audio_source(master_clock, context->clock_inc * NUM_OPERATORS, 2);
 	
 	//some games seem to expect that the LR flags start out as 1
 	for (int i = 0; i < NUM_CHANNELS; i++) {
@@ -191,7 +185,7 @@
 				fprintf(stderr, "Failed to open WAVE log file %s for writing\n", fname);
 				continue;
 			}
-			if (!wave_init(f, sample_rate, 16, 1)) {
+			if (!wave_init(f, master_clock / (context->clock_inc * NUM_OPERATORS), 16, 1)) {
 				fclose(f);
 				context->channels[i].logfile = NULL;
 			}
@@ -266,13 +260,10 @@
 
 void ym_free(ym2612_context *context)
 {
+	render_free_source(context->audio);
 	if (context == log_context) {
 		ym_finalize_log();
 	}
-	free(context->audio_buffer);
-	//TODO: Figure out how to make this 100% safe
-	//audio thread could still be using this
-	free(context->back_buffer);
 	free(context);
 }
 
@@ -475,59 +466,19 @@
 			uint16_t phase = operator->phase_counter >> 10 & 0x3FF;
 			operator->phase_counter += ym_calc_phase_inc(context, operator, context->current_op);
 			int16_t mod = 0;
-			switch (op % 4)
-			{
-			case 0://Operator 1
+			if (op & 3) {
+				if (operator->mod_src[0]) {
+					mod = *operator->mod_src[0];
+					if (operator->mod_src[1]) {
+						mod += *
+						operator->mod_src[1];
+					}
+					mod >>= YM_MOD_SHIFT;
+				}
+			} else {
 				if (chan->feedback) {
 					mod = (chan->op1_old + operator->output) >> (10-chan->feedback);
 				}
-				break;
-			case 1://Operator 3
-				switch(chan->algorithm)
-				{
-				case 0:
-				case 2:
-					//modulate by operator 2
-					mod = context->operators[op+1].output >> YM_MOD_SHIFT;
-					break;
-				case 1:
-					//modulate by operator 1+2
-					mod = (context->operators[op-1].output + context->operators[op+1].output) >> YM_MOD_SHIFT;
-					break;
-				case 5:
-					//modulate by operator 1
-					mod = context->operators[op-1].output >> YM_MOD_SHIFT;
-				}
-				break;
-			case 2://Operator 2
-				if (chan->algorithm != 1 && chan->algorithm != 2 && chan->algorithm != 7) {
-					//modulate by Operator 1
-					mod = context->operators[op-2].output >> YM_MOD_SHIFT;
-				}
-				break;
-			case 3://Operator 4
-				switch(chan->algorithm)
-				{
-				case 0:
-				case 1:
-				case 4:
-					//modulate by operator 3
-					mod = context->operators[op-2].output >> YM_MOD_SHIFT;
-					break;
-				case 2:
-					//modulate by operator 1+3
-					mod = (context->operators[op-3].output + context->operators[op-2].output) >> YM_MOD_SHIFT;
-					break;
-				case 3:
-					//modulate by operator 2+3
-					mod = (context->operators[op-1].output + context->operators[op-2].output) >> YM_MOD_SHIFT;
-					break;
-				case 5:
-					//modulate by operator 1
-					mod = context->operators[op-3].output >> YM_MOD_SHIFT;
-					break;
-				}
-				break;
 			}
 			uint16_t env = operator->envelope;
 			if (operator->ssg) {
@@ -607,7 +558,6 @@
 		if (context->current_op == NUM_OPERATORS) {
 			context->current_op = 0;
 			
-			context->buffer_fraction += context->buffer_inc;
 			int16_t left = 0, right = 0;
 			for (int i = 0; i < NUM_CHANNELS; i++) {
 				int16_t value = context->channels[i].output;
@@ -621,7 +571,7 @@
 						value |= 0xC000;
 					}
 				}
-				if (context->channels[i].logfile && context->buffer_fraction > BUFFER_INC_RES) {
+				if (context->channels[i].logfile) {
 					fwrite(&value, sizeof(value), 1, context->channels[i].logfile);
 				}
 				if (context->channels[i].lr & 0x80) {
@@ -631,30 +581,7 @@
 					right += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER;
 				}
 			}
-			int32_t tmp = left * context->lowpass_alpha + context->last_left * (0x10000 - context->lowpass_alpha);
-			left = tmp >> 16;
-			tmp = right * context->lowpass_alpha + context->last_right * (0x10000 - context->lowpass_alpha);
-			right = tmp >> 16;
-			while (context->buffer_fraction > BUFFER_INC_RES) {
-				context->buffer_fraction -= BUFFER_INC_RES;
-
-				int64_t tmp = context->last_left * ((context->buffer_fraction << 16) / context->buffer_inc);
-				tmp += left * (0x10000 - ((context->buffer_fraction << 16) / context->buffer_inc));
-				context->audio_buffer[context->buffer_pos] = tmp >> 16;
-				
-				tmp = context->last_right * ((context->buffer_fraction << 16) / context->buffer_inc);
-				tmp += right * (0x10000 - ((context->buffer_fraction << 16) / context->buffer_inc));
-				context->audio_buffer[context->buffer_pos+1] = tmp >> 16;
-				
-				context->buffer_pos += 2;
-				if (context->buffer_pos == context->sample_limit) {
-					if (!headless) {
-						render_wait_ym(context);
-					}
-				}
-			}
-			context->last_left = left;
-			context->last_right = right;
+			render_put_stereo_sample(context->audio, left, right);
 		}
 		
 	}
@@ -969,6 +896,103 @@
 				break;
 			case REG_ALG_FEEDBACK:
 				context->channels[channel].algorithm = value & 0x7;
+				switch (context->channels[channel].algorithm)
+				{
+				case 0:
+					//operator 3 modulated by operator 2
+					context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output;
+					context->operators[channel*4+1].mod_src[1] = NULL;
+					
+					//operator 2 modulated by operator 1
+					context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
+					
+					//operator 4 modulated by operator 3
+					context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output;
+					context->operators[channel*4+3].mod_src[1] = NULL;
+					break;
+				case 1:
+					//operator 3 modulated by operator 1+2
+					context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+0].output;
+					context->operators[channel*4+1].mod_src[1] = &context->operators[channel*4+2].output;
+					
+					//operator 2 unmodulated
+					context->operators[channel*4+2].mod_src[0] = NULL;
+					
+					//operator 4 modulated by operator 3
+					context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output;
+					context->operators[channel*4+3].mod_src[1] = NULL;
+					break;
+				case 2:
+					//operator 3 modulated by operator 2
+					context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output;
+					context->operators[channel*4+1].mod_src[1] = NULL;
+					
+					//operator 2 unmodulated
+					context->operators[channel*4+2].mod_src[0] = NULL;
+					
+					//operator 4 modulated by operator 1+3
+					context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output;
+					context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output;
+					break;
+				case 3:
+					//operator 3 unmodulated
+					context->operators[channel*4+1].mod_src[0] = NULL;
+					context->operators[channel*4+1].mod_src[1] = NULL;
+					
+					//operator 2 modulated by operator 1
+					context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
+					
+					//operator 4 modulated by operator 2+3
+					context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+2].output;
+					context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output;
+					break;
+				case 4:
+					//operator 3 unmodulated
+					context->operators[channel*4+1].mod_src[0] = NULL;
+					context->operators[channel*4+1].mod_src[1] = NULL;
+					
+					//operator 2 modulated by operator 1
+					context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
+					
+					//operator 4 modulated by operator 3
+					context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output;
+					context->operators[channel*4+3].mod_src[1] = NULL;
+					break;
+				case 5:
+					//operator 3 modulated by operator 1
+					context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+0].output;
+					context->operators[channel*4+1].mod_src[1] = NULL;
+					
+					//operator 2 modulated by operator 1
+					context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
+					
+					//operator 4 modulated by operator 1
+					context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output;
+					context->operators[channel*4+3].mod_src[1] = NULL;
+					break;
+				case 6:
+					//operator 3 unmodulated
+					context->operators[channel*4+1].mod_src[0] = NULL;
+					context->operators[channel*4+1].mod_src[1] = NULL;
+					
+					//operator 2 modulated by operator 1
+					context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
+					
+					//operator 4 unmodulated
+					context->operators[channel*4+3].mod_src[0] = NULL;
+					context->operators[channel*4+3].mod_src[1] = NULL;
+					break;
+				case 7:
+					//everything is an output so no modulation (except for op 1 feedback)
+					context->operators[channel*4+1].mod_src[0] = NULL;
+					context->operators[channel*4+1].mod_src[1] = NULL;
+					
+					context->operators[channel*4+2].mod_src[0] = NULL;
+					
+					context->operators[channel*4+3].mod_src[0] = NULL;
+					context->operators[channel*4+3].mod_src[1] = NULL;
+					break;
+				}
 				context->channels[channel].feedback = value >> 3 & 0x7;
 				//printf("Algorithm %d, feedback %d for channel %d\n", value & 0x7, value >> 3 & 0x7, channel);
 				break;