Fixing the sound lag on mame4all-pi

Fine tuning Mame4all_pi (2015-12) for vertical displays

A guide by Maarten Spoek

In my previous blog entry, I thought I fixed the sound lag with mame4all-pi, but that wasn’t true somehow the next morning… duh…
So I had to dive into the sound buffer. It seemed to me that the 60fps was not really 60fps, or not the same 60fps the alsa worker thread was running.
Maybe sometimes it was and sometimes it wasn’t.
Anyway, the only solution to fix this and not wanting to rewrite the whole sound buffer, is to under run the sound buffer, which will crackle the sound sometimes.

diff --git a/src/rpi/video.cpp b/src/rpi/video.cpp
index 7e6655d..e0a07f0 100644
--- a/src/rpi/video.cpp
+++ b/src/rpi/video.cpp
@@ -432,28 +440,37 @@ int osd_set_display(int width,int height,int depth,int attributes,int orientatio
 
 	vsync_frame_rate = video_fps;
 
-	if (video_sync)
+	if (video_sync) // you need to enable this in the mame.cfg ...
 	{
 		TICKER a,b;
 		float rate;

 
 		/* wait some time to let everything stabilize */
-		for (i = 0;i < 60;i++)
-		{
-			vsync();
-			a = ticker();
-		}

+		usleep(1000000); // for (i = 0;i < 100000;i++) ; 
-		/* small delay for really really fast machines */
-		for (i = 0;i < 100000;i++) ; 
-		a = ticker(); 
-  
-		vsync(); 
- 		b = ticker(); 
-  
-		rate = ((float)TICKS_PER_SEC)/(b-a); 
+		rate = (float)video_fps * 0.998; // underrun the sound   
-		logerror("target frame rate = %ffps, video frame rate = %3.2fHz\n",video_fps,rate); 
+		logerror("target frame rate = %dfps, video frame rate = %3.2fHz\n",video_fps,rate);
    		/* don't allow more than 8% difference between target and actual frame rate */
  		while (rate > video_fps * 108 / 100)
@@ -463,7 +480,7 @@ int osd_set_display(int width,int height,int depth,int attributes,int orientatio
 		{
 			osd_close_display();
 			logerror("-vsync option cannot be used with this display mode:\n"
-						"video refresh frequency = %dHz, target frame rate = %ffps\n",
+						"video refresh frequency = %dHz, target frame rate = %dfps\n",
 						(int)(TICKS_PER_SEC/(b-a)),video_fps);
 			return 0;
 		}
@@ -772,7 +789,7 @@ void osd_update_video_and_audio(struct osd_bitmap *bitmap)
 		{12,0,0,0,0,0,0,0,0,0,0,0 }
 	};
 	int i;
-	static int showfps,showfpstemp;
+	static int showfps = 0,showfpstemp = 0;
 	TICKER curr;
 	static TICKER prev_measure=0,this_frame_base,prev;
 	static int speed = 100;
@@ -825,12 +842,12 @@ void osd_update_video_and_audio(struct osd_bitmap *bitmap)
 			profiler_mark(PROFILER_IDLE);
 			if (video_sync)
 			{
-				static TICKER last;
+				static TICKER last = ticker();
 				do
 				{
-					vsync();
+					usleep(20); // vsync();
 					curr = ticker();
-				} while (TICKS_PER_SEC / (curr - last) > video_fps * 11 /10);
+				} while (TICKS_PER_SEC / (curr - last) >= video_fps);
 				last = curr;
 			}
 			else

So in addition to under running the sound buffer, I wrote some code to repeat the last sample when under running, instead of blanking it with zeros. This way, there is no cracking sound.

diff --git a/src/rpi/sound.cpp b/src/rpi/sound.cpp
index 7b74942..4366c16 100644
--- a/src/rpi/sound.cpp
+++ b/src/rpi/sound.cpp
@@ -123,13 +123,15 @@ void osd_stop_audio_stream(void)
 }
 
 #define min(a, b) ((a) period_size_bytes / alsa->period_size_frames;
+	UINT8 lastsample[MAXBYTESPERSAMPLE] = {0,0,0,0};
 	UINT8 *buf = (UINT8 *)calloc(1, alsa->period_size_bytes);
 	if (!buf)
 	{
@@ -153,21 +155,31 @@ static void alsa_worker_thread(void *data)
 		if(avail period_size_bytes)
 		{
 			slock_unlock(alsa->fifo_lock);
-			fifo_size = 0;
+			buf_size = 0;
 		}
 		else
 		{
-			fifo_size = min(alsa->period_size_bytes, avail);
-			if(fifo_size > alsa->period_size_bytes)
-				fifo_size = alsa->period_size_bytes;
-			fifo_read(alsa->buffer, buf, fifo_size);
+			buf_size = min(alsa->period_size_bytes, avail);
+			fifo_read(alsa->buffer, buf, buf_size);
 			scond_signal(alsa->cond);
 			slock_unlock(alsa->fifo_lock);
 		}
 	    
-		// If underrun, fill rest with silence.
- 		if(alsa->period_size_bytes != fifo_size) {
-			memset(buf + fifo_size, 0, alsa->period_size_bytes - fifo_size);
+		// If underrun, fill rest with last value (a silence will give crackle).
+ 		if ((buf_size >= bytes) && (bytes <= MAXBYTESPERSAMPLE)) {
+	 		// Read last sample in case of future underrun
+	 		for (int i=0; i<bytes; i++) {
+	 			lastsample[i] = buf[buf_size - bytes + i];
+	 		}
+	 	} else if(buf_size == 0) {
+	 		// now fill underrun with the value
+	 		for (int j=0; jperiod_size_bytes - buf_size;) {
+		 		// write last sample
+		 		for (int i=0; iperiod_size_bytes*3);
+		tempbuf=calloc(1, alsa->period_size_bytes*4);
 		snd_pcm_writei (alsa->pcm, tempbuf, 2 * alsa->period_size_frames);
 		free(tempbuf);
 	}
-
+	
 	alsa->fifo_lock = slock_new();
 	alsa->cond_lock = slock_new();
 	alsa->cond = scond_new();

Now when running my video screen @60Hz the sound is pretty much perfect.

Advertenties
Fixing the sound lag on mame4all-pi

Geef een reactie

Vul je gegevens in of klik op een icoon om in te loggen.

WordPress.com logo

Je reageert onder je WordPress.com account. Log uit / Bijwerken )

Twitter-afbeelding

Je reageert onder je Twitter account. Log uit / Bijwerken )

Facebook foto

Je reageert onder je Facebook account. Log uit / Bijwerken )

Google+ photo

Je reageert onder je Google+ account. Log uit / Bijwerken )

Verbinden met %s