
FIRtro en Raspberry 3
Re: FIRtro en Raspberry 3
muchas gracias, me lo pongo de tarea escolar 

Re: FIRtro en Raspberry 3
Hola,
comparto un experimento FIRtro-light con una Raspberry Pi 1 reciclada, que funciona.
(actualizado)
comparto un experimento FIRtro-light con una Raspberry Pi 1 reciclada, que funciona.
(actualizado)
Re: FIRtro en Raspberry 3
Hola a todos!!
Puff, que mal rato he pasado sin vuestro apoyo con la instalación y puesta en marcha de un FIRtro en RPI3.
Estoy muy agradecido a Rafa que me a apoyado en privado, a parte de todo el curro que cualquiera pensaría que se lo esta haciendo a medida a alguien
Comento que he probado FIRtro light y aun que vaya mejor todavía hay alguna corte y chasquido. En este tiempo de travesía en el desierto he aprendido bastantes cosillas. He logrado instalar brutefir sobre una instalación limpia, he creado un brutefir_config con xover de 2vias y DRC. He instalado y configurado shairport-sync (Y todo esto solo con letras!!!
). Ahora llevara unos 45`sonando perfecto y esta es la carga del procesador:
Esto es la carga con FIRtro-light cuando se entrecorta:
Y el brutefir_config
No se cual sera el problema con jack, recuerdo que cuando hice mi primera instalación lo hice con escritorio gráfico. El el patch de conexiones eran todas estables salvo las que venían del Shairport-sync. El problema està entre la entrada de audio y Ecasound o brutefir.
Estoy bastante contento con "esto", pero después de probar FIRtro, con su web, su volumen, ecualizador, loudness,cambio al vuelo de todos los parámetros... "esto" se me queda pequeño.
Puff, que mal rato he pasado sin vuestro apoyo con la instalación y puesta en marcha de un FIRtro en RPI3.
Estoy muy agradecido a Rafa que me a apoyado en privado, a parte de todo el curro que cualquiera pensaría que se lo esta haciendo a medida a alguien

Comento que he probado FIRtro light y aun que vaya mejor todavía hay alguna corte y chasquido. En este tiempo de travesía en el desierto he aprendido bastantes cosillas. He logrado instalar brutefir sobre una instalación limpia, he creado un brutefir_config con xover de 2vias y DRC. He instalado y configurado shairport-sync (Y todo esto solo con letras!!!

Código: Seleccionar todo
top - 22:34:38 up 14 min, 2 users, load average: 0.42, 0.43, 0.28
Tasks: 107 total, 1 running, 63 sleeping, 0 stopped, 0 zombie
%Cpu(s): 11.5 us, 0.8 sy, 0.0 ni, 87.6 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 949476 total, 782836 free, 65200 used, 101440 buff/cache
KiB Swap: 102396 total, 102396 free, 0 used. 814904 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
587 pi 20 0 28552 24132 9572 S 22.4 2.5 2:44.41 brutefir.real
586 pi 20 0 28552 24104 9544 S 21.4 2.5 2:45.36 brutefir.real
589 pi 20 0 76720 6964 5400 S 4.3 0.7 0:31.60 shairport-sync
5 root 20 0 0 0 0 I 1.3 0.0 0:03.59 kworker/u8:0
625 pi 20 0 8256 3384 2824 R 1.3 0.4 0:06.07 top
65 root -51 0 0 0 0 S 1.0 0.0 0:06.51 irq/92-mmc1
135 root 20 0 0 0 0 I 0.3 0.0 0:03.83 kworker/u8:2
1 root 20 0 27004 6064 4956 S 0.0 0.6 0:02.20 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H
6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_w
Código: Seleccionar todo
top - 21:46:57 up 3 min, 1 user, load average: 0.21, 0.18, 0.08
Tasks: 149 total, 1 running, 148 sleeping, 0 stopped, 0 zombie
%Cpu(s): 7.2 us, 3.3 sy, 0.0 ni, 88.8 id, 0.0 wa, 0.0 hi, 0.7 si, 0.0 st
KiB Mem : 949580 total, 595180 free, 116564 used, 237836 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 665184 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
816 firtro 20 0 167904 87604 85904 S 12.1 9.2 0:03.82 shairport-sync
795 firtro 20 0 123424 117460 89924 S 10.8 12.4 0:08.80 ecasound
787 firtro -7 0 99856 11664 9372 S 4.2 1.2 0:03.12 brutefir.real
788 firtro -7 0 99856 11688 9392 S 4.2 1.2 0:03.15 brutefir.real
763 firtro 20 0 98716 92016 85028 S 3.9 9.7 0:01.76 jackd
114 root 20 0 0 0 0 S 1.6 0.0 0:00.57 kworker/u8:2
87 root -51 0 0 0 0 S 1.0 0.0 0:00.62 irq/92-mmc1
848 firtro 20 0 8256 3384 2788 R 1.0 0.4 0:00.75 top
709 root 20 0 0 0 0 S 0.3 0.0 0:00.15 kworker/u8:3
780 firtro -6 0 100248 94688 92512 S 0.3 10.0 0:00.39 brutefir.real
812 firtro 20 0 170468 137412 101416 S 0.3 14.5 0:02.94 python
1 root 20 0 27072 6116 4944 S 0.0 0.6 0:02.25 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.02 ksoftirqd/0
4 root 20 0 0 0 0 S 0.0 0.0 0:00.13 kworker/0:0
Código: Seleccionar todo
sampling_rate: 44100;
filter_length: 8192,16;
float_bits: 32;
overflow_warnings: true;
allow_poll_mode: false;
monitor_rate: true;
powersave: -80;
lock_memory: true;
show_progress: false;
# --------------------------------
# ---------- DRC COEFFs ----------
# --------------------------------
coeff "c_drc1_L" {
filename: "/home/pi/brutefir/SS_Left_DRC";
format: "FLOAT_LE";
shared_mem: false;
attenuation: -1.0;
};
coeff "c_drc1_R" {
filename: "/home/pi/brutefir/SS_Right_DRC";
format: "FLOAT_LE";
shared_mem: false;
attenuation: -1.0;
};
## COEFF DEFAULTS ##
coeff "c-lo" {
filename: "/home/pi/brutefir/lp-SSW.pcm";
format: "FLOAT_LE";
shared_mem: false;
attenuation: -1.00;
};
coeff "c-hi" {
filename: "/home/pi/brutefir/lp-SST.pcm";
format: "FLOAT_LE";
shared_mem: false;
attenuation: -6.00;
};
## INPUT DEFAULTS ##
#
input "left_in", "right_in" {
device: "alsa" { device: "hw:Loopback,0"; ignore_xrun: true; };
# sample: "AUTO";
};
## OUTPUT analog
#
output "left_lo_out", "right_lo_out", "left_hi_out", "right_hi_out" {
device: "alsa" { device: "hw:LT3"; ignore_xrun: true; };
channels: 4/0,1,2,3;
sample: "S16_LE";
dither: true;
};
## FILTER DEFAULTS ##
# --- DRC filtering:
filter "f_drc_L" {
from_inputs: "left_in";
to_filters: "f_hi_L", "f_lo_L";
coeff: "c_drc1_L";
};
filter "f_drc_R" {
from_inputs: "right_in";
to_filters: "f_hi_R", "f_lo_R";
coeff: "c_drc1_R";
};
filter "f_hi_L" {
from_filters: "f_drc_L";
to_outputs: "left_hi_out";
coeff: "c-hi";
};
filter "f_lo_L" {
from_filters: "f_drc_L";
to_outputs: "left_lo_out";
coeff: "c-lo";
};
filter "f_hi_R" {
from_filters: "f_drc_R";
to_outputs: "right_hi_out";
coeff: "c-hi";
};
filter "f_lo_R" {
from_filters: "f_drc_R";
to_outputs: "right_lo_out";
coeff: "c-lo";
};
Estoy bastante contento con "esto", pero después de probar FIRtro, con su web, su volumen, ecualizador, loudness,cambio al vuelo de todos los parámetros... "esto" se me queda pequeño.
Re: FIRtro en Raspberry 3
Hola, viendo la carga de CPU no parece un problema de proceso. Lo típico de los cortes es un resampleo demasiado exigente para la CPU, pero no es el caso.
Solo como conjetura, investigaría como sospechoso a la conexión por red. No es mi tema, pero las conexiones de red en tiempo real pueden se puñeteras, y si son por wifi casi casi que no hay que mirar más allá.
¿Crees que pueden ir por ahí los tiros?
Solo como conjetura, investigaría como sospechoso a la conexión por red. No es mi tema, pero las conexiones de red en tiempo real pueden se puñeteras, y si son por wifi casi casi que no hay que mirar más allá.
¿Crees que pueden ir por ahí los tiros?
Re: FIRtro en Raspberry 3
No se, con wifi --> Shairport.sync --> alsa-loopback -->brutefir --> Salida Analógica no hay ningún corte ni chasquido ni nada de nada. PERFECTO. He probado hasta con 8192,32 y ni se menea, así que la wifi tendría que quedar descartada y la falta de potencia tambien. Yo pienso que tiene que ser algo de jack o algo corriendo en 2º plano no se...
Re: FIRtro en Raspberry 3
Bien, si descartas con motivo el wifi hay que mirar las opciones de jack en ~/audio/config.
Yo tengo:
jack_options = -R -dalsa -p512
La opción p: -p, --period Frames per period (default: 1024)
Puedes dejar el default para empezar. ¿Qué tienes ahí?
Yo tengo:
jack_options = -R -dalsa -p512
La opción p: -p, --period Frames per period (default: 1024)
Puedes dejar el default para empezar. ¿Qué tienes ahí?
Re: FIRtro en Raspberry 3
Hoola
La RPI con UCA202 es una combinación limitante.
No se por qué motivo pero necesita forzar el puerto usb a 1.1 (dwc_otg.speed=1). Ello en principio no debería ser un problema...
Jack con USB debe usar '-n3'
Brutefir recomienda no abusar del particionado, 16 es un valor exigente creo recordar.
Y creo que es preferible lock_memory:false; toda vez que esté desactivado el swap de disco.
En las pruebas que he hecho he notado interrupciones cuando por ejemplo estoy conectado por ssh y editando un archivo, al hacer scroll simplemente... aunque haya poco %CPU parece ser que JACK "no resulta bien atendido".
Creo que el motivo es que JACK usa la tarjeta de sonido en modo MMAP y eso se le atraganta a la RPI cuando tiene que hacer I/O por USB. Quizás por esto te va mejor si no usas Jack la tarjeta se usa en modo RW.
Ahora por ejemplo llevo un buen rato (>2h) usando una RPI2 con la UCA202 en duplex firtrando la entrada analógica y va bastante bien, con una latencia asumible incluso para material audiovisual:
Para usar un player como shairport (Airplay) o librespot (Spotify) es mejor reiniciar Jack con un period más alto.
La mejor opción para RPI es una tarjeta I2S, la Cirrus o la vieja Wolfson. Ahora he encontrado otra muy barata con LineIn/Out que probaré en breve
http://www.audioinjector.net/rpi-hat
(edito el link, en A.es sale a 18 leuros)
La RPI con UCA202 es una combinación limitante.
No se por qué motivo pero necesita forzar el puerto usb a 1.1 (dwc_otg.speed=1). Ello en principio no debería ser un problema...
Jack con USB debe usar '-n3'
Brutefir recomienda no abusar del particionado, 16 es un valor exigente creo recordar.
Y creo que es preferible lock_memory:false; toda vez que esté desactivado el swap de disco.
En las pruebas que he hecho he notado interrupciones cuando por ejemplo estoy conectado por ssh y editando un archivo, al hacer scroll simplemente... aunque haya poco %CPU parece ser que JACK "no resulta bien atendido".
Creo que el motivo es que JACK usa la tarjeta de sonido en modo MMAP y eso se le atraganta a la RPI cuando tiene que hacer I/O por USB. Quizás por esto te va mejor si no usas Jack la tarjeta se usa en modo RW.
Ahora por ejemplo llevo un buen rato (>2h) usando una RPI2 con la UCA202 en duplex firtrando la entrada analógica y va bastante bien, con una latencia asumible incluso para material audiovisual:
Código: Seleccionar todo
jackd -R -dalsa -p1024 -n3 --softmode --shorts -dhw:CODEC,0 -r44100
Código: Seleccionar todo
+ Brutefir
sampling_rate: 44100;
filter_length: 4096,1;
float_bits: 32;
overflow_warnings: true;
allow_poll_mode: false;
monitor_rate: true;
powersave: -80;
lock_memory: false;
show_progress: false;
Código: Seleccionar todo
+ Ecasound
8 paramétricos
La mejor opción para RPI es una tarjeta I2S, la Cirrus o la vieja Wolfson. Ahora he encontrado otra muy barata con LineIn/Out que probaré en breve

http://www.audioinjector.net/rpi-hat
(edito el link, en A.es sale a 18 leuros)
Última edición por Rafax el Mar Mar 13, 2018 6:33 pm, editado 1 vez en total.
Re: FIRtro en Raspberry 3
Hola, he estado haciendo otro tipo de pruebas lejos de FIRtro
. He instalado Kodi y hago pasar los 5.1 canales por brutefir con un filtro 8192,16 para cada canal, incluso he probado on 32 particiones. Y ni se cantea reproduciendo pelis 1080p. Osea, de potencia va sobrada.
A ver si esta tarde hago alguna prueba con FIRtro, aunque después de ver las opciones que tiene kodi, lo interesante seria ir añadiendo Loudness, ecualizacion, volumen y web a un kodi
, pero todavía no me veo capaz.
/etc/asound.conf
brutefir_config
NOTA: En brutefir_config la salida del sub esta nombrada como central y a la inversa 

A ver si esta tarde hago alguna prueba con FIRtro, aunque después de ver las opciones que tiene kodi, lo interesante seria ir añadiendo Loudness, ecualizacion, volumen y web a un kodi

/etc/asound.conf
Código: Seleccionar todo
# Create an ALSA default audio-device for the ALSA loopback-device.
pcm.!default {
# Use the ALSA plug-in "plug" for rate-/format-conversion.
type plug
# Forward the audio stream of OSMC/KODI to the ALSA loopback-device
slave {
pcm {
# Direct hardware access
type hw
# Loopback card name
#
# Has to match "id" in the options of the snd-aloop module
card "hw:Loopback"
# Loopback device ID
device 0
# Number of audio channels
#
# Has to match the number of channels in OSMC/KODI (e.g. 7.1 -> 8)
# and "channels" in the BruteFIR input configuration
channels 6
# Format of audio stream
#
# Has to match the format defined in the "sample"-tag
# of the BruteFIR input configuration
format "S16_LE"
# Sampling-rate of audio stream
#
# Has to match the sampling-rate defined in the global "sampling_rate"-tag
# of the global BruteFIR configuration
rate 44100
}
}
}
# Create an ALSA default control-device for the ALSA loopback-device.
ctl.!default {
# Direct hardware access
type hw
# Loopback card name
#
# Has to match "id" in the options of the snd-aloop module
card "hw:Loopback"
}
Código: Seleccionar todo
sampling_rate: 44100;
filter_length: 8192,16;
float_bits: 32;
overflow_warnings: false;
allow_poll_mode: false;
monitor_rate: false;
powersave: -80;
lock_memory: true;
show_progress: false;
# --------------------------------
# ---------- DRC COEFFs ----------
# --------------------------------
#coeff "c_drc1_L" {
# filename: "/home/osmc/brutefir/SS_Left_DRC";
# format: "FLOAT_LE";
# shared_mem: false;
# attenuation: -1.0;
#};
#coeff "c_drc1_R" {
# filename: "/home/osmc/brutefir/lp-SW_near+DRC.pcm";
# format: "FLOAT_LE";
# shared_mem: false;
# attenuation: -1.0;
#};
## COEFF DEFAULTS ##
coeff "c-sonus" {
filename: "/home/osmc/brutefir/Sonus/lp-Sonus_1m+near.pcm";
format: "FLOAT_LE";
shared_mem: false;
attenuation: -15.00;
};
coeff "c-bw" {
filename: "/home/osmc/brutefir/Sonus/lp-bw_1m.pcm";
format: "FLOAT_LE";
shared_mem: false;
attenuation: -15.00;
};
coeff "c-sw" {
filename: "/home/osmc/brutefir/Sonus/lp-SW_near+DRC.pcm";
format: "FLOAT_LE";
shared_mem: false;
attenuation: -15.00;
};
## INPUT DEFAULTS ##
input "left_front_in", "right_front_in", "left_rear_in", "right_rear_in" , "subwoofer_in", "center_in"{
device: "alsa" { device: "hw:Loopback,1"; ignore_xrun: true; };
channels: 6/0,1,2,3,4,5;
sample: "S16_LE";
};
## OUTPUT analog
#
output "left_front", "right_front" , "left_rear", "right_rear" , "subwoofer_out", "central_out" {
device: "alsa" { device: "hw:LT3"; ignore_xrun: true; };
channels: 6/0,1,2,3,4,5;
sample: "S16_LE";
dither: true;
};
## FILTER DEFAULTS ##
# --- DRC filtering:
filter "left_front" {
from_inputs: "left_front_in", "subwoofer_in"/6/1;
to_outputs: "left_front";
coeff: "c-sonus";
};
filter "right_front" {
from_inputs: "right_front_in", "subwoofer_in"/6/1;
to_outputs: "right_front";
coeff: "c-sonus";
};
filter "left_rear" {
from_inputs: "left_rear_in";
to_outputs: "left_rear";
delay: 1 ;
coeff: "c-bw";
};
filter "right_rear" {
from_inputs: "right_rear_in";
to_outputs: "right_rear";
delay: 1 ;
coeff: "c-bw";
};
filter "subwoofer" {
from_inputs: "subwoofer_in";
to_outputs: "subwoofer_out";
coeff: "c-bw";
};
filter "central" {
from_inputs: "left_front_in", "right_front_in", "left_rear_in", "right_rear_in" , "subwoofer_in", "center_in";
to_outputs: "central_out";
coeff: "c-sw";
};

Re: FIRtro en Raspberry 3
Me parece que la causa de que Jack sea delicado en RPI es que Jack accede a la tarjeta de sonido en modo MMAP, debido a que necesita contruir una estructura de muestras de acceso directo en memoria para poder establecer cualquier interconexión entre puertos.
Creo que algo debe atascarse en la RPI quizás por el chipset de I/O y la memoria para que el modo MMAP sea delicado con la UCA202.
Las aplicaciones que no son servers de audio (como Brutefir) suelen usan la tarjeta ALSA en modo RW.
No obstante, hice unas pruebas como las que has puesto, es decir entrando a Brutefir desde ALSA hw:Loopback y saliendo por ALSA hw:tarjeta_de_sonido y al rato se desmadraba, como que perdía el sincronismo. Quizás se me escapó algo ¿?
FIRtro está pensado con Jack, pero sería posible hacer una variante adaptada sin Jack, ya que las funciones de volumen, loudness, tonos, room_curves, etc no dependen de Jack
Creo que algo debe atascarse en la RPI quizás por el chipset de I/O y la memoria para que el modo MMAP sea delicado con la UCA202.
Las aplicaciones que no son servers de audio (como Brutefir) suelen usan la tarjeta ALSA en modo RW.
No obstante, hice unas pruebas como las que has puesto, es decir entrando a Brutefir desde ALSA hw:Loopback y saliendo por ALSA hw:tarjeta_de_sonido y al rato se desmadraba, como que perdía el sincronismo. Quizás se me escapó algo ¿?
FIRtro está pensado con Jack, pero sería posible hacer una variante adaptada sin Jack, ya que las funciones de volumen, loudness, tonos, room_curves, etc no dependen de Jack

Re: FIRtro en Raspberry 3
Jack es imprescindible para el enrutado de audio cuando se usan diferentes entradas. Es decir, es imprescindible para hacer del FIRtro lo que lo hace único: puede realizar todas las funciones de un previo clásico. Sin jack es un servidor de música digital con funciones de proceso añadidas. Interesante, pero hay miles, como lo que sugerías, rarranzb, de un kodi con cosas detrás.
El mundo del software libre, como el HUM, es adicto al corta y pega, al pathwork y al collage, de modo que todo está hecho de trozos de otras cosas, con algo nuevo o genuino, o con un montaje diferente. Así que usar trozos de firtro y hacer otra cosa está genial, pero será otra cosa.
El mundo del software libre, como el HUM, es adicto al corta y pega, al pathwork y al collage, de modo que todo está hecho de trozos de otras cosas, con algo nuevo o genuino, o con un montaje diferente. Así que usar trozos de firtro y hacer otra cosa está genial, pero será otra cosa.
Re: FIRtro en Raspberry 3
Para mi es un must, yo prefiero con Jack, ya que obliga a cualquier fuente a adaptarse a las reglas estrictas del formato de audio del sistema, o a la inversa.
Pero creo que si no se necesitan entradas externas no es imprescindible el conmutador del previo, lo que facilita que funcione en máquinas pequeñas.
- DRC
- Room curves
- Volumen calibrable.
- Escuchas a bajo SPL asistidas con loudness calibrado
- Control de tonos
¿Miles con todo esto?
Pero creo que si no se necesitan entradas externas no es imprescindible el conmutador del previo, lo que facilita que funcione en máquinas pequeñas.
- XOver(FIRtro) sin jack es un servidor de música digital con funciones de proceso añadidas. Interesante, pero hay miles,
- DRC
- Room curves
- Volumen calibrable.
- Escuchas a bajo SPL asistidas con loudness calibrado
- Control de tonos
¿Miles con todo esto?
Re: FIRtro en Raspberry 3
No, claro. Pero con alguna cosa sí. Pero con selector de entradas y proceso adicional... previos digitales comerciales. Y eso cambia la arquitectura más que ninguna otra de las anteriores.
Pero en fin, molamos
Pero en fin, molamos

Re: FIRtro en Raspberry 3
Entiendo que kodi+brutefir no es FIRtro ni mucho menos. Yo no logro hacerlo funcionar correctamente. Este "chapuz" lo he montado para poder escuchar de una vez los xover y el DRC. Aunque una vez probado me gusta la idea de sustituir mi apple TV por algo semejante pero con filtros digitales.
Como otra de las premisas principales es hacerlo "low cost" la raspberry es la candidata ideal pero jack se ha interpuesto en el camino, porque de potencia ya hemos visto que tiene de sobra.
Hay que recordar que las pruebas no solo las he hecho con la UCA, si no que también con una tarjeta de 6 canales de salida, con la integrada en la RPI y con una I2C. Siempre he obtenido cortes, con unas menos que con otras pero nunca bien. Sin Jack la cosa cambia, y es que no he vuelto a escuchar nada raro y eso que esta en 6 canales con filtros relativamente largos.
Como otra de las premisas principales es hacerlo "low cost" la raspberry es la candidata ideal pero jack se ha interpuesto en el camino, porque de potencia ya hemos visto que tiene de sobra.
Hay que recordar que las pruebas no solo las he hecho con la UCA, si no que también con una tarjeta de 6 canales de salida, con la integrada en la RPI y con una I2C. Siempre he obtenido cortes, con unas menos que con otras pero nunca bien. Sin Jack la cosa cambia, y es que no he vuelto a escuchar nada raro y eso que esta en 6 canales con filtros relativamente largos.
Re: FIRtro en Raspberry 3
También se puede usar el apple TV como una fuente s/pdif del FIRtro (así lo tengo)sustituir mi apple TV
Re: FIRtro en Raspberry 3
Pues nada, como era de esperar va phenomenal.Rafax escribió:... he encontrado otra muy barata I2S con LineIn/Out que probaré en breve
http://www.audioinjector.net/rpi-hat
(edito el link, en A.es sale a 18 leuros)
Es un poco beta pero por su precio está bien. La circuitería es muy simplona, nada que ver con una Cirrus/Wolfson y la manufactura demasiado lowcost, eso no mola. Quedaría medir la respuesta en cuanto a ruido y tal ...
Parece que es de una empresa kickstart de esas de unos frikis, eso tiene su mérito: han hecho hasta una de 8 canales con salidas opcionalmente balanceadas, qué tíos

Y por cierto tienen hasta una overlay propia en el kernel oficial de Raspbian.