IR remote translater

Receive an IR code & retransmit a different code

Using Ken Shirriff's excellent IRremote Library


A while back I bought a second hand amplifier for use with our living room stereo. The amp came with a large infrared remote controller intended to control multiple devices from the same vendor.
Now only owning the amp this ment this lovely jewel of a remote control — CNC machined from a large piece of solid aluminium — we only utilized 5 of its 35 buttons.

There's no doubt the initial high cost of this amplifier when new not only stems from its technology and parts used, but also from its lovely satin (sandblasted) anodized finished CNC machined aluminium chassis. It would be sad to waste this remote in a drawer replaced with cheap plastic multi controller. But rather than trying to modify the remote itself I looked for a solution to translate its protocol and retransmit codes our other equipment could understand.

From all the Arduino IR projects I encountered Ken Shirriff's IRremote Library seamed to be the one best meeting my need. Ken's library take care of all the heavy lifting decoding infrared light pulses and creating new pulses.

Prototype very handy placed on top of my laptop screen.


I used an 2$ Arduino Nano clone and followed Ken's instruction hooking up receiver output to PIN 11 and IR LED transmitter to PIN 3. These parts where also sourced of eBay as no-name components searching for 38kHz IR receiver and infrared LED 940nm.
I used on-board LED on PIN 13 for visual representation of code transmitting.


BMC IR Remote

Code prinisipple

I had some initial problems making the code work until I understood the IR transmission had to wait to after the receiver interups where back operating again. i.e. one test for results and only store them to a variable, then resume receive operation before responding to result.

You probably don't have any of the remotes used here, but still you could upload the sketch to your Arduino board and read out IR code values your controllers give you. And then copy paste these IR codes into the sketch for quick testing of a few buttons before alter code to your requirement.

Download code ino file for Arduino Most web browsers will open ino files as plain text.

Note: Some code are missing from preview below due to how PHP render includes on my webserver. Use the download link above to get full code.
Sorry for unspecific code formatting. It's my take on a compromise for quick editing and easy reading.

/* Retransmit B.M.C. CS2 Amp IR multicontroller code as Pioneer D6 
 * or DV-656A or SqueezeBox Touch or Sony MiniDisc or Samsung TV 
 * and TOSLINK input selector
 * IR code depending on value of variable 'transport'
 * Pioneer D6 remote can also control the CS2 amp
 * beta 0.21-2019 Hans R Lønningdal
 * Known issue - IR transmitter diode used are very directional
 * Using Ken Shirriff's IRremote Library
#include   //

#define DBUG; // comment out this line for production code. DEBUG already taken by Ken :)
#ifdef DBUG
 #define SP(x)    Serial.print (x)
 #define SPLN(x)  Serial.println (x) 
 #define SPHEX(x) Serial.print ("0x"); Serial.println (x, HEX)
 #define SP(x)
 #define SPLN(x)
 #define SPHEX(x)

unsigned int RECV_PIN = 11;
unsigned int STATUS_PIN = 13;
IRrecv irrecv(RECV_PIN);
IRsend irsend;
decode_results results;     // results from received IR code
unsigned long newvalue;     // IR code to transmit
unsigned long buttonbefore; // remember last reseived button IR code value
unsigned int device = 0;    // used to define special feature for the remote send options
unsigned int onetofour = 1; // using up/down for direct 1-4 selection on optical input selector
unsigned int transport = 1; // BMC CD PROG button alter this value
const unsigned int CD  = 1; // Pioneer PD D6-MK2 SACD transport
const unsigned int SB  = 2; // SqueezeBox Touch
const unsigned int MD  = 3; // Sony MDE-JE770 MiniDisc
const unsigned int DAC = 4; // DAC controls used to control TOSLINK selector
const unsigned int TV =  5; // Samsung TV (2016) UE60KS7005
const unsigned int DV  = 6; // Pioneer DV-656A DVD Audio / CD transport
const unsigned int AMP = 7; // B.M.C. CS2 amp

void transportStatus(unsigned int activeLED) {
  // adjust for digital pins used to visualize transport status
  for (int i = 4; i <= 6; i++) {
    digitalWrite(i, LOW);
  digitalWrite(activeLED + 3, HIGH);

void sendCode(unsigned long button) {
  digitalWrite(13, HIGH); // Arduino LED
  // handle repeats from B.M.C. & many others. Needed as DV-656A don't 
  // use repeat code but prefix command code with a fixed 32-bit value
  if (button == 0xFFFFFFFF) {
    // we don't want to increment Up/Down input selector for 
    // DAC device so we keep repeat code as is
    // luckely the optical selector use this repeat code
    if (device != DAC) {button = buttonbefore;}
  } else {
    buttonbefore = button; 
  device = 0;
  // 'transport' is default CD=1, new users should test with this branch, or change 'transport' value
  if (transport == CD) {  // verified with Pioneer D6-MK2 SACD player
    switch (button) { 
      case 0x618650AF:  newvalue = 0x45BA38C7;  device = CD;  SPLN("Power"); break; // Pioneer D6 Power (CD DISP)
      case 0x6186708F:  newvalue = 0x45BA8A75;  device = CD;  SPLN("Tray");  break; // Pioneer D6 Tray  (CD REP)
      case 0x618610EF:  newvalue = 0x45BAE817;  device = CD;  SPLN("Play");  break; // Pioneer D6 Play
      case 0x6186906F:  newvalue = 0x45BA6897;  device = CD;  SPLN("Stop");  break; // Pioneer D6 Stop
      case 0x618630CF:  newvalue = 0x45BA708F;  device = CD;  SPLN("FFW");   break; // Pioneer D6 Fast Forward
      case 0x6186B04F:  newvalue = 0x45BAF00F;  device = CD;  SPLN("FRW");   break; // Pioneer D6 Fast Rewind
      case 0x618620DF:  newvalue = 0x45BA8877;  device = CD;  SPLN("Prew");  break; // Pioneer D6 Prew
      case 0x618600FF:  newvalue = 0x45BA08F7;  device = CD;  SPLN("Next");  break; // Pioneer D6 Next                             
      case 0x618648B7:  newvalue = 0x45BA807F;  device = CD;  SPLN("1");     break; // Pioneer D6 1
      case 0x6186C837:  newvalue = 0x45BA40BF;  device = CD;  SPLN("2");     break; // Pioneer D6 2
      case 0x61868877:  newvalue = 0x45BAC03F;  device = CD;  SPLN("3");     break; // Pioneer D6 3
      case 0x618608F7:  newvalue = 0x45BA20DF;  device = CD;  SPLN("4");     break; // Pioneer D6 4
      case 0x6186F00F:  newvalue = 0x45BAA05F;  device = CD;  SPLN("5");     break; // Pioneer D6 5
      case 0x618618E7:  newvalue = 0x45BA609F;  device = CD;  SPLN("6");     break; // Pioneer D6 6
      case 0x6186E817:  newvalue = 0x45BAE01F;  device = CD;  SPLN("7");     break; // Pioneer D6 7
      case 0x618628D7:  newvalue = 0x45BA10EF;  device = CD;  SPLN("8");     break; // Pioneer D6 8
      case 0x6186A857:  newvalue = 0x45BA906F;  device = CD;  SPLN("9");     break; // Pioneer D6 9
      case 0x61866897:  newvalue = 0x45BA00FF;  device = CD;  SPLN("0");     break; // Pioneer D6 0 
      case 0x618658A7:  newvalue = 0x45BA18E7;  device = CD;  SPLN("Pause"); break; // Pioneer D6 Pause (CD CHECK)
      case 0x61869867:  newvalue = 0x45BAA25D;  device = CD;  SPLN("Clear"); break; // Pioneer D6 Clear
  if (transport == SB) {  // verified with SqueezeBox Touch - NEC 32-bit, first 4 digits 0x7689#### are
                          // device/manufactor idetifier, or 16-bit pre-data as it called in lirc's database 
    switch (button) {     //
      case 0x618650AF:  newvalue = 0x76897887; device = SB;  SPLN("Display"); break; // SqueezeBox Display Now Playing
      case 0x6186708F:  newvalue = 0x768938C7; device = SB;  SPLN("Repeat");  break; // SqueezeBox Repeat
      case 0x618610EF:  newvalue = 0x768910EF; device = SB;  SPLN("Play");  break; // SqueezeBox Play (will power on the Touch) 
      case 0x6186906F:  newvalue = 0x768920DF; device = SB;  SPLN("Stop");  break; // SqueezeBox Stop (actually Pause)
      case 0x618630CF:  newvalue = 0x7689A05F; device = SB;  SPLN("FFW");   break; // SqueezeBox Fast Forward
      case 0x6186B04F:  newvalue = 0x7689C03F; device = SB;  SPLN("FRW");   break; // SqueezeBox Fast Rewind
      case 0x618620DF:  newvalue = 0x7689C03F; device = SB;  SPLN("Prew");  break; // SqueezeBox Prew
      case 0x618600FF:  newvalue = 0x7689A05F; device = SB;  SPLN("Next");  break; // SqueezeBox Next                         
      case 0x618648B7:  newvalue = 0x7689F00F; device = SB;  SPLN("1");     break; // SqueezeBox 1
      case 0x6186C837:  newvalue = 0x768908F7; device = SB;  SPLN("2");     break; // SqueezeBox 2
      case 0x61868877:  newvalue = 0x76898877; device = SB;  SPLN("3");     break; // SqueezeBox 3
      case 0x618608F7:  newvalue = 0x768948B7; device = SB;  SPLN("4");     break; // SqueezeBox 4
      case 0x6186F00F:  newvalue = 0x7689C837; device = SB;  SPLN("5");     break; // SqueezeBox 5
      case 0x618618E7:  newvalue = 0x768928D7; device = SB;  SPLN("6");     break; // SqueezeBox 6
      case 0x6186E817:  newvalue = 0x7689A857; device = SB;  SPLN("7");     break; // SqueezeBox 7
      case 0x618628D7:  newvalue = 0x76896897; device = SB;  SPLN("8");     break; // SqueezeBox 8
      case 0x6186A857:  newvalue = 0x7689E817; device = SB;  SPLN("9");     break; // SqueezeBox 9
      case 0x61866897:  newvalue = 0x76899867; device = SB;  SPLN("0");     break; // SqueezeBox 0
      case 0x618658A7:  newvalue = 0x768940BF; device = SB;  SPLN("Power"); break; // SqueezeBox Power  (CD CHECK)
      case 0x61869867:  newvalue = 0x768922DD; device = SB;  SPLN("Home");  break; // SqueezeBox Home   (CD CLEAR)
  if (transport == MD) {  // not verified - IR codes from Sony MDE-JE770 remote
    switch (button) {
      case 0x618650AF:  newvalue = 0xA9E; device = MD;  SPLN("Power"); break; // Sony Power
      case 0x6186708F:  newvalue = 0x69E; device = MD;  SPLN("Tray");  break; // Sony Tray     
      case 0x618610EF:  newvalue = 0x55E; device = MD;  SPLN("Play");  break; // Sony Play
      case 0x6186906F:  newvalue = 0x15E; device = MD;  SPLN("Stop");  break; // Sony Stop
      case 0x618630CF:  newvalue = 0x35E; device = MD;  SPLN("FFW");   break; // Sony Fast Forward
      case 0x6186B04F:  newvalue = 0xD5E; device = MD;  SPLN("FRW");   break; // Sony Fast Rewind
      case 0x618620DF:  newvalue = 0x5E;  device = MD;  SPLN("Prew");  break; // Sony Prew
      case 0x618600FF:  newvalue = 0x85E; device = MD;  SPLN("Next");  break; // Sony Next                         
      case 0x618648B7:  newvalue = 0x1E;  device = MD;  SPLN("1");     break; // Sony 1
      case 0x6186C837:  newvalue = 0x81E; device = MD;  SPLN("2");     break; // Sony 2
      case 0x61868877:  newvalue = 0x41E; device = MD;  SPLN("3");     break; // Sony 3
      case 0x618608F7:  newvalue = 0xC1E; device = MD;  SPLN("4");     break; // Sony 4
      case 0x6186F00F:  newvalue = 0x21E; device = MD;  SPLN("5");     break; // Sony 5
      case 0x618618E7:  newvalue = 0xA1E; device = MD;  SPLN("6");     break; // Sony 6
      case 0x6186E817:  newvalue = 0x61E; device = MD;  SPLN("7");     break; // Sony 7
      case 0x618628D7:  newvalue = 0xE1E; device = MD;  SPLN("8");     break; // Sony 8
      case 0x6186A857:  newvalue = 0x11E; device = MD;  SPLN("9");     break; // Sony 9
      case 0x61866897:  newvalue = 0x91E; device = MD;  SPLN("0");     break; // Sony 0
      case 0x618658A7:  newvalue = 0x95E; device = MD;  SPLN("Pause"); break; // Sony Pause (CD CHECK)
      case 0x61869867:  newvalue = 0xF1E; device = MD;  SPLN("Clear"); break; // Sony Clear (CD CLEAR)
  if (transport == DV) {  // verified with Pioneer DV-656A DVD Audio / CD transport
    switch (button) { 
      case 0x618650AF:  newvalue = 0xF50A3DC2;  device = DV;  SPLN("Power"); break; // DV-656A Power (CD DISP)
      case 0x6186708F:  newvalue = 0xF50A6D92;  device = DV;  SPLN("Tray");  break; // DV-656A Tray  (CD REP)
      case 0x618610EF:  newvalue = 0xC53A7986;  device = DV;  SPLN("Play");  break; // DV-656A Play
      case 0x6186906F:  newvalue = 0xC53A19E6;  device = DV;  SPLN("Stop");  break; // DV-656A Stop
      case 0x618630CF:  newvalue = 0xF50A9768;  device = DV;  SPLN("FFW");   break; // DV-656A Fast Forward
      case 0x6186B04F:  newvalue = 0xF50A57A8;  device = DV;  SPLN("FRW");   break; // DV-656A Fast Rewind
      case 0x618620DF:  newvalue = 0xC53AB946;  device = DV;  SPLN("Prew");  break; // DV-656A Prew
      case 0x618600FF:  newvalue = 0xC53A39C6;  device = DV;  SPLN("Next");  break; // DV-656A Next                             
      case 0x618648B7:  newvalue = 0xF50A857A;  device = DV;  SPLN("1");     break; // DV-656A 1
      case 0x6186C837:  newvalue = 0xF50A45BA;  device = DV;  SPLN("2");     break; // DV-656A 2
      case 0x61868877:  newvalue = 0xF50AC53A;  device = DV;  SPLN("3");     break; // DV-656A 3
      case 0x618608F7:  newvalue = 0xF50A25DA;  device = DV;  SPLN("4");     break; // DV-656A 4
      case 0x6186F00F:  newvalue = 0xF50AA55A;  device = DV;  SPLN("5");     break; // DV-656A 5
      case 0x618618E7:  newvalue = 0xF50A659A;  device = DV;  SPLN("6");     break; // DV-656A 6
      case 0x6186E817:  newvalue = 0xF50AE51A;  device = DV;  SPLN("7");     break; // DV-656A 7
      case 0x618628D7:  newvalue = 0xF50A15EA;  device = DV;  SPLN("8");     break; // DV-656A 8
      case 0x6186A857:  newvalue = 0xF50A956A;  device = DV;  SPLN("9");     break; // DV-656A 9
      case 0x61866897:  newvalue = 0xF50A05FA;  device = DV;  SPLN("0");     break; // DV-656A 0 
      case 0x618658A7:  newvalue = 0xC53AF906;  device = DV;  SPLN("Pause");  break;// DV-656A Pause (CD CHECK)
      case 0x61869867:  newvalue = 0x0;         device = 0;   SPLN(" ");     break; // CD CLEAR - device=0 ensure nothing is transmitet
  if (transport == TV) {  // Samsung TV using generic codes, this 2016 model comes with Bluetooth remote
    switch (button) {     //
      case 0x618650AF:  newvalue = 0xE0E040BF; device = TV;  SPLN("Power"); break; // SqueezeBox Power

  /*-- DAC secton of B.M.C. remote --*/
  switch (button) {
    case 0x8666609F: // DAC DF
      newvalue = 0x0; // 
      device = 0x0; //device = DAC;
      SPLN("DAC DF");
    case 0x8666619E: // DAC OVS
      newvalue = newvalue = 0xE0E0D02F; // Samsung TV - Volume Ned
      device = TV;
      SPLN("DAC OVS");
    case 0x8666629D: // DAC UPS
      newvalue = newvalue = 0xE0E0E01F; // Samsung TV - Volume Opp
      device = TV;
      SPLN("DAC UPS");
    case 0x86662AD5: // DAC IN UP
      if (newvalue != 0xFFFFFFFF ) {onetofour++;}
      if (onetofour >= 5) {onetofour = 1;}
      if (onetofour == 1) {newvalue = 0x1FE807F;} // Optical Selector 1
      if (onetofour == 2) {newvalue = 0x1FE20DF;} // Optical Selector 2
      if (onetofour == 3) {newvalue = 0x1FEE01F;} // Optical Selector 3
      if (onetofour == 4) {newvalue = 0x1FE50AF;} // Optical Selector 4      
      device = DAC;
      #ifdef DBUG
        SPLN("DAC Input Down");
        SP("onetofour = "); SPLN(onetofour); 
    case 0x8666AA55: // DAC IN DOWN
      if (newvalue != 0xFFFFFFFF) {onetofour--;}
      if (onetofour <= 0) {onetofour = 4;}    
      if (onetofour == 1) {newvalue = 0x1FE807F;} // Optical Selector 1
      if (onetofour == 2) {newvalue = 0x1FE20DF;} // Optical Selector 2
      if (onetofour == 3) {newvalue = 0x1FEE01F;} // Optical Selector 3
      if (onetofour == 4) {newvalue = 0x1FE50AF;} // Optical Selector 4
      device = DAC;
      #ifdef DBUG
        SPLN("DAC Input Down");
        SP("onetofour = "); SPLN(onetofour); 
    case 0x8666728D: // DAC MUTE
      newvalue = 0x1FE58A7; // Optical Selector On/Off
      device = DAC;
      SPLN("DAC MUTE");
    case 0x866640BF: // DAC VOL UP
      newvalue = 0x0; // Optical Selector
      device = DAC;
      SPLN("DAC VOL UP");
    case 0x866641BE: // DAC VOL DOWN
      newvalue = 0x0; // Optical Selector
      device = DAC;
    /*-- B.M.C. CD PROGRAM button used to alter internal tranport value --*/
    case 0x6186D02F: 
      if (transport >= 6) {transport = 1;} // DV-656A left out for now
      delay(200); // dirty way to supress repeats
      SPLN("CD Program");
      SP("transport = "); SPLN(transport);
    /*-- Control B.M.C. from Pioneer D6 remote - verified --*/
    case 0xA55A50AF:
      newvalue = 0x866602FD; // Volume Up
      device = AMP;
    case 0xA55AD02F:
      newvalue = 0x8666827D; // Volume Down
      device = AMP;      
    case 0xA55A48B7:
      newvalue = 0x8666A659; // Mute
      device = AMP;      
    /*-- Pioneer D6 remote Amp Power button used to alter Input Up selector on B.M.C. CS2 --*/
    case 0xA55A38C7: 
      newvalue = 0x8666C639; // B.M.C. CS2 Input Up will start ower from Phono 1 after XRL 2
      device = AMP;      
  } // end switch

    // finaly we're ready to send new IR code
    if (device >= 1) {      
      switch (device) {
        case CD:  irsend.sendNEC(newvalue, 32); break;    // Pioneer D6 use NEC 32-bit and quicly repeats the same code
        case AMP: irsend.sendNEC(newvalue, 32); 
                  irsend.sendNEC(0xFFFFFFFF, 32); break;  // B.M.C. use NEC 32-bit and seem to prefer at a fixed 32-bit repeat command at the end
        case DV:  irsend.sendNEC(0xC53A9966, 32); 
                  irsend.sendNEC(newvalue, 32); break;    // DV-656A use NEC 32-bit with the 32-bit prefix 0xC53A9966
        case DAC: irsend.sendNEC(newvalue, 32); break;    // S/P DIF Optical Selector use NEC 32 bit
        case SB:  irsend.sendNEC(newvalue, 32); delay(5); // SB Touch seem to like a couple 
                  irsend.sendNEC(newvalue, 32); delay(5); // of repeats to give solid response
                  irsend.sendNEC(newvalue, 32); break;    // 
        case MD:  irsend.sendSony(newvalue, 12); break;   // Sony MD use Sony 12-bit - not verified
        case TV:  irsend.sendNEC(newvalue, 32);           // Samsung TV (2016) actually comes with Bluetooth Smart Control
                  delay(3); break;                        // need several repeats of the same code but seems more reliable with a short delay
    #ifdef DBUG 
      SP("Code sent: "); SPHEX(newvalue);
    } else {
      SPLN("This code not registered with any device.");
    digitalWrite(13, LOW);

void encoding (int type) {
  switch (type) {
    case UNKNOWN:      SP("UNKNOWN");       break ;
    case NEC:          SP("NEC");           break ;
    case SONY:         SP("SONY");          break ;
    case RC5:          SP("RC5");           break ;
    case RC6:          SP("RC6");           break ;
    case DISH:         SP("DISH");          break ;
    case SHARP:        SP("SHARP");         break ;
    case JVC:          SP("JVC");           break ;
    case SANYO:        SP("SANYO");         break ;
    case MITSUBISHI:   SP("MITSUBISHI");    break ;
    case SAMSUNG:      SP("SAMSUNG");       break ;
    case LG:           SP("LG");            break ;
    case WHYNTER:      SP("WHYNTER");       break ;
    case AIWA_RC_T501: SP("AIWA_RC_T501");  break ;
    case PANASONIC:    SP("PANASONIC");     break ;
    case DENON:        SP("Denon");         break ;
  SP(" ");

void setup() {
  #ifdef DBUG 
    while (!Serial);
  irrecv.enableIRIn(); // Start the receiver

void loop() {
  newvalue = 0x0;
  if (irrecv.decode(&results)) {
    newvalue = results.value;
    #ifdef DBUG
      // Check if the buffer overflowed
      if (results.overflow) {
        SPLN("IR code too long. Edit IRremoteInt.h and increase RAWBUF");
      SP(results.bits); SP("-bits"); SP(" ");
        if(results.address > 0x0){SPHEX(results.address); SP(" ");}
    irrecv.resume(); // Receive the next value  
  if (newvalue > 0x0) {
    //SPLN("Call sendCode");
/* Circuit
* IR receiver output to pin 11, 5V and ground
* IR LED transmiter anode to 100R resistor, other end of resistor to pin 3, IR LED cathode to ground

Project & Code Evolution

When I had the Pioneer CD transport working I wondered how to make use of the DAC section of the B.M.C. controller. My Audio-GD DAC has no remote so that has to be a project for later. But I do have an optical S/P DIF selector box. It has 4 inputs where any of the four inputs can be routed to two independed outputs. Very handy where I can have a seperate output going to my MiniDisc player where I can select digital sourche to record from and still choose something else to monitor — similar to what vintage receivers used to have for tape decks and recorder.

Original IR remote for this device select inputs on numbered 1-4 direct buttons. My new main controller only has Up/Down available so some simple code had to be worked out. It has one caveat and that is it asume we always start at input 1 at power-on. The device itself remember active inputs at soft start. Still, current code is only one pushbutton away from becomming in sync until next power cycle.

It occurred to me I might be able to control my Squeezebox Touch if I make a "device selector" for several audio transports in software — effectively making my B.M.C. controller a hard to program multi controller.

B.M.C. use real tactile switches, — combined with custom programed repeats for the different devices give a great feel where device usually respond with a single button click.

Screen dump

S/P DIF optical selector


One suprising attribute with the IR translate hub combined with B.M.C. remote and Pioneer DV-656A are much faster button response. I dedicate this to slow power-on handling in the original Pioneer remote.

Pioneer DV-656A

B.M.C. Audio CS2 amp IR remote codes
Input Up 	0x8666C639 followed by 0xFFFFFFFF
Input Down	0x866626D9 followed by 0xFFFFFFFF
Volume Up 	0x866602FD followed by 0xFFFFFFFF
Volume Down	0x8666827D followed by 0xFFFFFFFF
Mute 		0x8666A659 followed by 0xFFFFFFFF
When muted the amp will ignore all commands until unmuted. 

To view high resolution images, right click on image and select View image or Save image

Select file from list below



Your comment are welcome


Email: optional, will be hidden