I am trying to understand how does software code interface with other software or hardware?
At the very lowest level, software talks to hardware devices by accessing the hardware device's interface.
This is most easily seen with some very simple, old CPUs like the 8086, or modern microcontrollers like the PIC 16 series.
A common way of doing this is for the peripheral to intercept memory access (so called memory mapped). The peripheral essentially appears to software as a memory location. For example, the PIC16 series chips have a series of pins which can be used for digital inputs (e.g. switches). To access them, the software just accesses a memory location specified in the MCU manual. Inside the MCU, a series of logic gates intercept the signals going to the RAM, and when they detect a read to the specified address, instead sends the state of the pins.
Some CPUs like the x86 series had a second bus for peripherals, so that peripherals didn't have to sit on the high speed memory bus. x86 CPUs have a specific instructions that send/receive signals on this second port - and historically, this port would connect to the ISA bus, serial ports, etc. These days, these buses no longer exist in the same way and this stuff is all emulated. Most peripherals in a modern PC are memory mapped, and the job of the memory controller is to work out what reads/writes go to RAM and which should be routed to a PCI-E port (as well as much, much more).
In a modern OS, all this low-level stuff is handled by the OS and drivers, with the OS providing a universal, stable interface - often called an abstraction layer. There are a variety of methods that OSs use for permitting software to access OS functions: software triggered interrupts, tables of addresses to jump to, etc.
The OS designer provides a mechanism for software to request a specific hardware function. The OS and the hardware driver then translate that function into specific proprietary requests from the actual hardware itself. This permits software to function in a consistent way with different hardware.
In the early days of PCs, software had to be specifically designed for specific makes and models of hardware. E.g. if you wanted to play a game, you'd have to check whether the game was compatible with your sound card. There was no OS driver at that stage, the game developers had to have bought the programming manual from the card manufacturer and coded the sound system specifically for that make and model of card.