Bläddra i källkod

equalizer - release

Philippe G 5 år sedan
förälder
incheckning
394d6b6465

+ 1 - 0
README.md

@@ -330,6 +330,7 @@ See squeezlite command line, but keys options are
 	- per mad & few others, edit configure and change $ac_link to add -c (faking link)
 	- change ac_files to remove ''
 	- add DEPS_CFLAGS and DEPS_LIBS to avoid pkg-config to be required
+	- stack consumption can be very high with some codec variants, so set NONTHREADSAFE_PSEUDOSTACK and GLOBAL_STACK_SIZE=32000 and unset VAR_ARRAYS in config.h
 - better use helixaac			
 - set IDF_PATH=/home/esp-idf
 - set ESPPORT=COM9

+ 10 - 0
components/audio/component.mk

@@ -0,0 +1,10 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+COMPONENT_ADD_LDFLAGS=-l$(COMPONENT_NAME) 	\
+	$(COMPONENT_PATH)/lib/libesp_processing.a
+	
+
+	
+	

+ 78 - 0
components/audio/inc/esp_equalizer.h

@@ -0,0 +1,78 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+// All rights reserved.
+
+#ifndef _ESP_EQUALIZER_H
+#define _ESP_EQUALIZER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+* @brief      Initialize the equalizer handle
+*
+* @param      nch     The audio channel number
+* @param      g_rate  The audio sample rate. Four sample rates are supported: 11025Hz, 22050Hz, 44100Hz and 48000Hz.
+* @param      n_band  The number of audio sub-bands. Fixed number of 10 sub-bands is supported and this value should be set to 10.
+* @param      use_xmms_original_freqs  Currently should be set 0
+*
+* @return     The equalizer handle.
+*/
+void *esp_equalizer_init(int nch, int g_rate, int n_band, int use_xmms_original_freqs);
+
+/**
+* @brief     Uninitialize the equalizer handle.
+*
+* @param      handle   The the equalizer handle
+*/
+void esp_equalizer_uninit(void *handle);
+
+/**
+* @brief      Process the data through the equalizer
+*
+* @param      handle   The the equalizer handle
+* @param      pcm_buf  The audio pcm input & output buffer
+* @param      length   The length of current bytes in pcm_buf
+* @param      g_rate   The audio sample rate. Four sample rates are supported: 11025Hz, 22050Hz, 44100Hz and 48000Hz.
+* @param      nch      The audio channel number
+*
+* @return     Length of pcm_buf after processing
+*/
+int esp_equalizer_process(void *handle, unsigned char *pcm_buf, int length, int g_rate, int nch);
+
+/**
+* @brief      Set the number of sub-bands for the equalizer
+*
+* @param      handle  The the equalizer handle
+* @param      value   The audio sub-bands gain. unit:db. 0 means no gain.
+* @param      index   The index of audio sub-bands. e.g. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
+* @param      nch     The audio channel number
+*/
+void esp_equalizer_set_band_value(void *handle, float value, int index, int nch);
+
+/**
+* @brief      Get the number of the equalizer sub-bands
+*
+* @param      handle   The the equalizer handle
+*
+* @return     The number of the equalizer sub-bands
+*/
+int esp_equalizer_get_band_count(void *handle);
+
+/**
+* @brief      Get the value of the equalizer sub-bands
+*
+* @param      handle  The the equalizer handle
+* @param      index   The index of audio sub-bands. Currently only support 10 sub-bands, so it should be 0-9.
+* @param      nch     The audio channel number
+*
+* @return     The number of the equalizer sub-bands
+*/
+float esp_equalizer_get_band_value(void *handle, int index, int nch);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

BIN
components/audio/lib/libesp_processing.a


+ 2 - 1
components/squeezelite/component.mk

@@ -15,7 +15,8 @@ CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ON
 	-I$(COMPONENT_PATH)/../codecs/inc/opusfile	\
 	-I$(COMPONENT_PATH)/../driver_bt			\
 	-I$(COMPONENT_PATH)/../raop					\
-	-I$(COMPONENT_PATH)/../services
+	-I$(COMPONENT_PATH)/../services				\
+	-I$(COMPONENT_PATH)/../audio/inc
 
 #	-I$(COMPONENT_PATH)/../codecs/inc/faad2
 

+ 89 - 0
components/squeezelite/equalizer.c

@@ -0,0 +1,89 @@
+/* 
+ *  Squeezelite for esp32
+ *
+ *  (c) Philippe G. 2020, philippe_44@outlook.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+ 
+#include "squeezelite.h" 
+#include "equalizer.h"
+#include "esp_equalizer.h"
+ 
+#define EQ_BANDS	10
+
+static log_level loglevel = lINFO;
+ 
+static struct {
+	void *handle;
+	float gain[EQ_BANDS];
+	bool update;
+} equalizer = { .update = true };
+ 
+/****************************************************************************************
+ * open equalizer
+ */
+void equalizer_open(u32_t sample_rate) {
+	if (sample_rate != 11025 && sample_rate != 22050 && sample_rate != 44100 && sample_rate != 48000) {
+		LOG_WARN("equalizer only supports 11025, 22050, 44100 and 48000 sample rates, not %u", sample_rate);
+		return;
+	}	
+	
+	equalizer.handle = esp_equalizer_init(2, sample_rate, EQ_BANDS, 0);
+	equalizer.update = false;
+    
+	if (equalizer.handle) {
+		LOG_INFO("equalizer initialized");
+		for (int i = 0; i < EQ_BANDS; i++) {
+			esp_equalizer_set_band_value(equalizer.handle, equalizer.gain[i], i, 0);
+			esp_equalizer_set_band_value(equalizer.handle, equalizer.gain[i], i, 1);
+		}
+	} else {
+		LOG_WARN("can't init equalizer");
+	}	
+}	
+
+/****************************************************************************************
+ * close equalizer
+ */
+void equalizer_close(void) {
+	if (equalizer.handle) {
+		esp_equalizer_uninit(equalizer.handle);
+		equalizer.handle = NULL;
+	}
+}	
+
+/****************************************************************************************
+ * update equalizer gain
+ */
+void equalizer_update(s8_t *gain) {
+	for (int i = 0; i < EQ_BANDS; i++) equalizer.gain[i] = gain[i];
+	equalizer.update = true;
+}
+
+/****************************************************************************************
+ * process equalizer 
+ */
+void equalizer_process(u8_t *buf, u32_t bytes, u32_t sample_rate) {
+	// don't want to process with output locked, so tak ethe small risk to miss one parametric update
+	if (equalizer.update) {
+		equalizer_close();
+		equalizer_open(sample_rate);
+	}
+	
+	if (equalizer.handle) {
+		esp_equalizer_process(equalizer.handle, buf, bytes, sample_rate, 2);
+	}	
+}

+ 26 - 0
components/squeezelite/equalizer.h

@@ -0,0 +1,26 @@
+/* 
+ *  Squeezelite for esp32
+ *
+ *  (c) Philippe G. 2020, philippe_44@outlook.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+ 
+#pragma once
+
+void equalizer_open(u32_t sample_rate);
+void equalizer_close(void);
+void equalizer_update(s8_t *gain);
+void equalizer_process(u8_t *buf, u32_t bytes, u32_t sample_rate);

+ 4 - 0
components/squeezelite/output_bt.c

@@ -21,6 +21,7 @@
  
 #include "driver/gpio.h"
 #include "squeezelite.h"
+#include "equalizer.h"
 #include "perf_trace.h"
 #include "config.h"
 
@@ -84,6 +85,7 @@ void output_close_bt(void) {
 	running = false;
 	UNLOCK;
 	hal_bluetooth_stop();
+	equalizer_close();
 }	
 
 static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
@@ -155,6 +157,8 @@ int32_t output_bt_data(uint8_t *data, int32_t len) {
 		SET_MIN_MAX(wanted_len, under);
 	}
 	output.frames_in_process = len-wanted_len;
+	
+	equalizer_process(data, (len - wanted_len) * BYTES_PER_FRAME, output.current_sample_rate);
 
 	UNLOCK;
 	SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time);

+ 31 - 0
components/squeezelite/output_embedded.c

@@ -19,10 +19,13 @@
  *
  */
 #include "squeezelite.h"
+#include "equalizer.h"
 
 extern struct outputstate output;
 extern struct buffer *outputbuf;
 
+static bool (*slimp_handler_chain)(u8_t *data, int len);
+
 #define FRAME_BLOCK MAX_SILENCE_FRAMES
 
 #define LOCK   mutex_lock(outputbuf->mutex)
@@ -47,11 +50,39 @@ static log_level loglevel;
 static bool (*volume_cb)(unsigned left, unsigned right);
 static void (*close_cb)(void);
 
+#pragma pack(push, 1)
+struct eqlz_packet {
+	char  opcode[4];
+};
+#pragma pack(pop)
+
+static bool handler(u8_t *data, int len){
+	bool res = true;
+	
+	if (!strncmp((char*) data, "eqlz", 4)) {
+		s8_t *gain = (s8_t*) (data + sizeof(struct eqlz_packet));
+		LOG_INFO("got equalizer %d", len);
+		// update will be done at next opportunity
+		equalizer_update(gain);
+	} else {
+		res = false;
+	}
+	
+	// chain protocol handlers (bitwise or is fine)
+	if (*slimp_handler_chain) res |= (*slimp_handler_chain)(data, len);
+	
+	return res;
+}
+
 void output_init_embedded(log_level level, char *device, unsigned output_buf_size, char *params, 
 						  unsigned rates[], unsigned rate_delay, unsigned idle) {
 	loglevel = level;						
 	LOG_INFO("init device: %s", device);
 	
+	// chain handlers
+	slimp_handler_chain = slimp_handler;
+	slimp_handler = handler;
+	
 	memset(&output, 0, sizeof(output));
 	output_init_common(level, device, output_buf_size, rates, idle);
 	output.start_frames = FRAME_BLOCK;

+ 10 - 1
components/squeezelite/output_i2s.c

@@ -53,6 +53,7 @@ sure that using rate_delay would fix that
 #include "monitor.h"
 #include "config.h"
 #include "accessors.h"
+#include "equalizer.h"
 #include "globdefs.h"
 
 #define LOCK   mutex_lock(outputbuf->mutex)
@@ -137,7 +138,7 @@ static void jack_handler(bool inserted) {
 /****************************************************************************************
  * amp GPIO
  */
-void set_amp_gpio(int gpio, char *value) {
+static void set_amp_gpio(int gpio, char *value) {
 	if (!strcasecmp(value, "amp")) {
 		amp_gpio = gpio;
 		
@@ -314,6 +315,8 @@ void output_close_i2s(void) {
 	i2s_driver_uninstall(CONFIG_I2S_NUM);
 	free(obuf);
 	
+	equalizer_close();
+	
 	adac->deinit();
 }
 
@@ -483,9 +486,15 @@ static void *output_thread_i2s(void *arg) {
 			i2s_config.sample_rate = output.current_sample_rate;
 			i2s_set_sample_rates(CONFIG_I2S_NUM, spdif ? i2s_config.sample_rate * 2 : i2s_config.sample_rate);
 			i2s_zero_dma_buffer(CONFIG_I2S_NUM);
+			
+			equalizer_close();
+			equalizer_open(output.current_sample_rate);
 			//return;
 		}
 		
+		// run equalizer
+		equalizer_process(obuf, oframes * bytes_per_frame, output.current_sample_rate);
+		
 		// we assume that here we have been able to entirely fill the DMA buffers
 		if (spdif) {
 			spdif_convert((ISAMPLE_T*) obuf, oframes, (u32_t*) sbuf, &count);

BIN
plugin/SqueezeESP32.zip


+ 7 - 0
plugin/SqueezeESP32/Player.pm

@@ -15,6 +15,12 @@ sub hasIR { 0 }
 
 sub init {
 	my $client = shift;
+	
+	$prefs->client($client)->init( { 
+		eq => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+		}
+	);	
+	
 	$client->SUPER::init(@_);
 	Plugins::SqueezeESP32::Plugin::config_artwork($client);
 }
@@ -55,6 +61,7 @@ sub reconnect {
 	my $client = shift;
 	$client->pluginData('artwork_md5', '');
 	$client->SUPER::reconnect(@_);
+	Plugins::SqueezeESP32::Plugin::send_equalizer($client);
 }	
 
 1;

+ 9 - 1
plugin/SqueezeESP32/PlayerSettings.pm

@@ -30,7 +30,7 @@ sub page {
 
 sub prefs {
 	my ($class, $client) = @_;
-	my @prefs = qw(width small_VU spectrum artwork);
+	my @prefs = qw(width small_VU spectrum artwork eq);
 	return ($prefs->client($client), @prefs);
 }
 
@@ -55,6 +55,13 @@ sub handler {
 		$client->display->modes($client->display->build_modes);
 		$client->display->update;
 		
+		my $eq = $cprefs->get('eq');
+		for my $i (0 .. $#{$eq}) {
+			$eq->[$i] = $paramRef->{"pref_eq.$i"};
+		}
+		$cprefs->set('eq', $eq);
+		Plugins::SqueezeESP32::Plugin::send_equalizer($client);
+		
 		# force update or disable artwork
 		if ($artwork->{'enable'}) {
 			Plugins::SqueezeESP32::Plugin::update_artwork($client, 1);
@@ -72,6 +79,7 @@ sub handler {
 	# logic of "Settings" is beyond me and I really hate it
 	$paramRef->{'pref_spectrum'} = $cprefs->get('spectrum');
 	$paramRef->{'pref_artwork'} = $cprefs->get('artwork');
+	$paramRef->{'pref_eq'} = $cprefs->get('eq');
 	
 	return $class->SUPER::handler($client, $paramRef);
 }

+ 8 - 2
plugin/SqueezeESP32/Plugin.pm

@@ -56,8 +56,6 @@ sub onNotification {
     my $client  = $request->client;
 	
 	my $reqstr     = $request->getRequestString();
-	$log->info("artwork update notification $reqstr");
-	#my $path = $request->getParam('_path');
 
 	update_artwork($client);
 }
@@ -108,6 +106,14 @@ sub send_artwork {
 	}
 }	
 
+sub send_equalizer {
+	my ($client) = @_;
+	my $equalizer = $prefs->client($client)->get('eq');
+	my $size = @$equalizer;
+	my $data = pack("c[$size]", @{$equalizer});
+	$client->sendFrame( eqlz => \$data );
+}
+
 sub config_artwork {
 	my ($client) = @_;
 	my $artwork = $prefs->client($client)->get('artwork');

+ 1 - 1
plugin/SqueezeESP32/install.xml

@@ -10,6 +10,6 @@
   <name>PLUGIN_SQUEEZEESP32</name>
   <description>PLUGIN_SQUEEZEESP32_DESC</description>
   <module>Plugins::SqueezeESP32::Plugin</module>
-    <version>0.72</version>
+    <version>0.80</version>
   <creator>Philippe</creator>
 </extensions>

+ 5 - 1
plugin/SqueezeESP32/strings.txt

@@ -14,7 +14,7 @@ PLUGIN_SQUEEZEESP32_DESC
 	EN	Adds a new player id (100) to enable display with SqueezeESP32
 	
 PLUGIN_SQUEEZEESP32_PLAYERSETTINGS
-	EN	Display (ESP32)
+	EN	ESP32 settings
 	
 PLUGIN_SQUEEZEESP32_WIDTH
 	EN	Screen width
@@ -69,3 +69,7 @@ PLUGIN_SQUEEZEESP32_ARTWORK_X
 
 PLUGIN_SQUEEZEESP32_ARTWORK_Y
 	EN	Y
+	
+PLUGIN_SQUEEZEESP32_EQUALIZER
+	EN	Parametric equalizer
+

+ 2 - 2
plugin/repo.xml

@@ -1,10 +1,10 @@
 <?xml version='1.0' standalone='yes'?>
 <extensions>
   <plugins>
-    <plugin version="0.72" name="SqueezeESP32" minTarget="7.5" maxTarget="*">
+    <plugin version="0.80" name="SqueezeESP32" minTarget="7.5" maxTarget="*">
       <link>https://github.com/sle118/squeezelite-esp32</link>
       <creator>Philippe</creator>
-      <sha>50679aff5e938359342d3a4d8251dcd25fab3eff</sha>
+      <sha>91e29c4380ce11728692f1cdabab080d1924a8d3</sha>
       <email>philippe_44@outlook.com</email>
       <desc lang="EN">SqueezeESP32 additional player id (100)</desc>
       <url>http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip</url>